创建一个带有任何签名的 "do-nothing" `std::function`?
Create a "do-nothing" `std::function` with any signature?
我想创建一个带有任意签名的简单无操作 std::function
对象。为此,我创建了两个函数:
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
// The "default-initialize-and-return" lambda
return [](ArgsProto...)->RESULT { return {}; };
}
template <typename... ArgsProto>
std::function<void(ArgsProto...)> GetFuncNoOp()
{
// The "do-nothing" lambda
return [](ArgsProto...)->void {};
}
其中每一个都运行良好(很明显,第一个版本可能会在 RESULT
对象中创建未初始化的数据成员,但在实践中我认为这不是什么大问题)。但是第二个,void
-返回版本是必要的,因为 return {};
never returns void
(这将是一个编译错误),并且它不能写成第一个的模板特化,因为初始签名是可变的。
所以我不得不在这两个功能之间做出选择,只实现一个,或者给它们不同的名称。但是我 真正 想要的只是轻松地初始化 std::function
对象,这样在调用时它们什么都不做而不是抛出异常。这可能吗?
注意 the default constructor of std::function
does not do what I want.
你戴牙套太执着了
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
// && avoids unnecessary copying. Thanks @Yakk
return [](ArgsProto&&...) { return RESULT(); };
}
template <class T> struct dummy {
static auto get() -> T { return {}; }
};
template <> struct dummy<void> {
static auto get() -> void {}
};
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
return [](ArgsProto...)->RESULT { return dummy<RESULT>::get(); };
}
但是...@T.C。解决方案要优雅得多。只是想展示另一种方法,它可以应用于任何你需要专注于某事的地方。"part"。
我不喜欢必须指定签名。
假设您有一个 std::function
实现,其中 std::function<void()>
可以接受类型 int(*)()
的函数指针,这是一个非类型擦除的 noop
对象投射到任何 std::function
:
struct noop {
struct anything {
template<class T>
operator T(){ return {}; }
// optional reference support. Somewhat evil.
template<class T>
operator T&()const{ static T t{}; return t; }
};
template<class...Args>
anything operator()(Args&&...)const{return {};}
};
如果您的 std::function
不支持该转换,我们添加:
template<class...Args>
operator std::function<void(Args...)>() {
return [](auto&&...){};
}
假设您的 std::function
是 SFINAE 友好的,这应该可以处理这种情况。
要使用,只需使用noop{}
。如果你真的需要一个返回 noop 的函数,请执行 inline noop GetFuncNoop(){ return{}; }
.
这样做的一个附带好处是,如果您将 noop
传递给非类型擦除操作,我们就不会因为什么都不做而得到毫无意义的 std::function
开销。
引用支持是邪恶的,因为它创建了一个全局对象并在所有地方传播对它的引用。如果一个 std::function<std::string&()>
被调用,并且结果 string
被修改,修改后的字符串将在所有地方使用(并且在使用之间没有任何同步)。加上不告诉任何人分配全球资源似乎很粗鲁。
我只是 =delete
operator T&
情况,并生成编译时错误。
我想创建一个带有任意签名的简单无操作 std::function
对象。为此,我创建了两个函数:
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
// The "default-initialize-and-return" lambda
return [](ArgsProto...)->RESULT { return {}; };
}
template <typename... ArgsProto>
std::function<void(ArgsProto...)> GetFuncNoOp()
{
// The "do-nothing" lambda
return [](ArgsProto...)->void {};
}
其中每一个都运行良好(很明显,第一个版本可能会在 RESULT
对象中创建未初始化的数据成员,但在实践中我认为这不是什么大问题)。但是第二个,void
-返回版本是必要的,因为 return {};
never returns void
(这将是一个编译错误),并且它不能写成第一个的模板特化,因为初始签名是可变的。
所以我不得不在这两个功能之间做出选择,只实现一个,或者给它们不同的名称。但是我 真正 想要的只是轻松地初始化 std::function
对象,这样在调用时它们什么都不做而不是抛出异常。这可能吗?
注意 the default constructor of std::function
does not do what I want.
你戴牙套太执着了
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
// && avoids unnecessary copying. Thanks @Yakk
return [](ArgsProto&&...) { return RESULT(); };
}
template <class T> struct dummy {
static auto get() -> T { return {}; }
};
template <> struct dummy<void> {
static auto get() -> void {}
};
template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
return [](ArgsProto...)->RESULT { return dummy<RESULT>::get(); };
}
但是...@T.C。解决方案要优雅得多。只是想展示另一种方法,它可以应用于任何你需要专注于某事的地方。"part"。
我不喜欢必须指定签名。
假设您有一个 std::function
实现,其中 std::function<void()>
可以接受类型 int(*)()
的函数指针,这是一个非类型擦除的 noop
对象投射到任何 std::function
:
struct noop {
struct anything {
template<class T>
operator T(){ return {}; }
// optional reference support. Somewhat evil.
template<class T>
operator T&()const{ static T t{}; return t; }
};
template<class...Args>
anything operator()(Args&&...)const{return {};}
};
如果您的 std::function
不支持该转换,我们添加:
template<class...Args>
operator std::function<void(Args...)>() {
return [](auto&&...){};
}
假设您的 std::function
是 SFINAE 友好的,这应该可以处理这种情况。
要使用,只需使用noop{}
。如果你真的需要一个返回 noop 的函数,请执行 inline noop GetFuncNoop(){ return{}; }
.
这样做的一个附带好处是,如果您将 noop
传递给非类型擦除操作,我们就不会因为什么都不做而得到毫无意义的 std::function
开销。
引用支持是邪恶的,因为它创建了一个全局对象并在所有地方传播对它的引用。如果一个 std::function<std::string&()>
被调用,并且结果 string
被修改,修改后的字符串将在所有地方使用(并且在使用之间没有任何同步)。加上不告诉任何人分配全球资源似乎很粗鲁。
我只是 =delete
operator T&
情况,并生成编译时错误。