作者热门文章
- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个非常好的包装器,但我希望它能接受任意数量的 T、S、R、Q、...
template<typename U, typename T, typename S>
boost::variant<U, std::string> RunSafeFn2(const std::function<U(const T&,const S&)>& f, const std::string& errMsg, const T& a1, const S& a2)
{
try
{
return f(a1,a2);
}
catch (...)
{
return errMsg;
}
}
我尝试了下面的内容并一直在谷歌搜索,但是错误消息是神秘的 - 我正在尝试做的事情甚至可能吗?
template<typename U, class ... Ts>
boost::variant<U, std::string> RunSafeFnN(const std::function<U(Ts)>& f, const std::string& errMsg, Ts ... ts)
{
try
{
return bind(f, ts...);
}
catch (...)
{
return errMsg;
}
}
最佳答案
你可以做你想做的,正如这个简单的程序所示:
template <class ... Ts>
void foo(std::function<void(Ts...)> f, Ts && ... ts) {
f(std::forward<Ts>(ts)...);
}
int main()
{
std::function<void(int)> f = [] (int i) { std::cerr << "hello " << i; };
foo(f, 5);
return 0;
}
问题是,一旦 RunSafeFn2
是一个模板,您也可以模板化仿函数本身。当您已经是模板时,键入删除可调用对象几乎没有什么好处。所以在实践中,这样做更有意义:
template <class F, class ... Ts>
void foo(F f, Ts && ... ts) {
f(std::forward<Ts>(ts)...);
}
这仍然允许上面的用法,但也允许做:
foo([] (int i) { std::cerr << "hello " << i; }, 5);
这也会更有效,因为您完全避免创建 std::function
对象。要处理返回类型,由于您仅限于 C++11,您可以这样做:
template <class F, class ... Ts>
auto foo(F f, Ts && ... ts) -> boost::variant<decltype(f(std::forward<Ts>(ts)...)), std::string> {
try {
return f(std::forward<Ts>(ts)...);
}
...
}
编辑:让我添加一个最后的想法:在 C++11 及更高版本中,可调用对象很容易创建,一个更简单的替代方法实际上是采用可调用对象并且没有参数:
template <class F>
auto foo(F f) -> boost::variant<decltype(f()), std::string> {
try {
return f();
}
...
}
那是因为围绕您需要的参数很容易捕捉到。例如,如果我以这种方式编写了我的原始示例,我可以通过执行以下操作来使用它:
int i = 5;
foo([&] () { std::cerr << "hello " << i; });
这有利有弊,尤其是在处理仅移动类型时,但如果您想最大程度地减少维护负担并且您的用例很简单,这是一个合理的选择。
关于c++ - 如何将 std::function 包装器转换为可变参数函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46594720/
我是一名优秀的程序员,十分优秀!