如何将std :: function包装器转换为可变参数函数?

时间:2017-10-05 21:00:54

标签: c++ c++11 boost variadic-templates

我有这个非常好的包装,但我希望它接受任意数量的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;
    }
}

1 个答案:

答案 0 :(得分:6)

你可以做你想做的事,正如这个简单的程序所示:

The property 'add' cannot be found on this object. Verify that the property exists and can be set.
At line:1 char:1
+ $names.add = Foreach ($A in $grps.keys) {Get-DistributionGroupMember -Identity ' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

问题是,一旦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); 对象,因此效率也会更高。要处理返回类型,因为你只能使用C ++ 11,你可以这样做:

std::function

编辑:让我添加一个最后的想法:在C ++ 11及其中,callables很容易创建,更简单的替代方法实际上是采用可调用的 no 参数:

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

那是因为很容易捕捉到你需要的论据。例如,如果我以这种方式编写了我的原始示例,我可以通过执行以下操作来使用它:

template <class F>
auto foo(F f) -> boost::variant<decltype(f()), std::string> {
    try {
        return f();
    }
    ...
}

这有利有弊,尤其是在处理移动类型时,但如果您想最大限度地减少维护负担并且您的用例很简单,那么这是一个合理的选择。