如何将std :: function包装器转换为可变参数函数?
问题描述:
我有这个非常漂亮的包装,但我想它接受任何数量的T,S,R,Q,...的如何将std :: function包装器转换为可变参数函数?
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; });
与移动只有类型时,这有利弊尤其是可能的,但如果你希望尽量减少维修负担,你的用例很简单,这是一个合理的选择。
从Clang开始,我得到'error:声明类型包含在函数'中的'Ts'下面带有波形的未扩展参数包'Ts''。如果我要判断,我会说这很清楚。 – chris
当然,但是它告诉我要做什么? – Carbon