如何将 std::function 包装器转换为可变参数函数?
Posted
技术标签:
【中文标题】如何将 std::function 包装器转换为可变参数函数?【英文标题】:How do I convert a std::function wrapper into a variadic function? 【发布时间】:2017-10-05 21:00:54 【问题描述】:我有这个非常好的包装器,但我希望它接受任意数量的 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;
【问题讨论】:
从 Clang 中,我得到error: declaration type contains unexpanded parameter pack 'Ts'
,在 function<U(Ts)>
的 Ts
下带有波浪线。如果我要判断,我会说这很清楚。
当然,但它告诉我该怎么做?
【参考方案1】:
你可以做你想做的事,正如这个简单的程序所示:
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 及更高版本中,可调用对象非常容易创建,一个更简单的替代方法实际上是采用可调用对象和 no 参数:
template <class F>
auto foo(F f) -> boost::variant<decltype(f()), std::string>
try
return f();
...
那是因为很容易捕捉到您需要的参数。例如,如果我以这种方式编写原始示例,我可以通过以下方式使用它:
int i = 5;
foo([&] () std::cerr << "hello " << i; );
这有利有弊,尤其是在处理仅移动类型时,但如果您想最大程度地减少维护负担并且您的用例很简单,这是一个合理的选择。
【讨论】:
好吧,bind 是一个完全的红鲱鱼。它用于从另一个创建一个可调用对象。但是您不想创建可调用对象,只想调用它。 std::forward 对于调用这样的可调用对象并不是绝对必要的,但由于各种原因,它是最正确的方法。 你能在 C++14 中为返回类型做一些更好的事情吗?我们在 MSVC 2015.2 是的,你的最终想法是我最初所做的,直到人们希望能够编写自己的失败包装器,并在失败包装器中包含参数。 @ProbablyAStupidQuestion 好吧,看看我的更新,总体上简化了很多事情。我实际上不确定 14 中是否有一个简单的简化;我本来想只使用 auto 但后来我意识到这与返回变体不太兼容。 它更优雅,但如果你通过 args,他们可以做一些聪明的事情,例如根据 args 检查返回。以上是关于如何将 std::function 包装器转换为可变参数函数?的主要内容,如果未能解决你的问题,请参考以下文章
包装器和绑定器std::bind和std::function的回调技术
包装器和绑定器std::bind和std::function的回调技术