如何将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; 
    } 
} 
+1

从Clang开始,我得到'error:声明类型包含在函数'中的'Ts'下面带有波形的未扩展参数包'Ts''。如果我要判断,我会说这很清楚。 – chris

+0

当然,但是它告诉我要做什么? – Carbon

你可以做你想做的,因为这个简单的程序显示:

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; }); 

与移动只有类型时,这有利弊尤其是可能的,但如果你希望尽量减少维修负担,你的用例很简单,这是一个合理的选择。

+0

所以魔法是使用std :: forward而不是绑定? – Carbon

+1

好吧,绑定是一个全红鲱鱼。它被用来创建一个从另一个可调用。但是你不想创建一个可调用的对象,你只需要调用它。对于像这样调用可调用函数,std :: forward并不是绝对必要的,但它是出于各种原因最正确的方法。 –

+0

你能在C++ 14中做什么更好的返回类型吗?我们正在使用MSVC 2015.2 – Carbon