简体   繁体   English

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

[英]How do I convert a std::function wrapper into a variadic function?

I have this very nice wrapper, but I'd like it to accept any number of T, S, R, Q, ... 我有这个非常好的包装,但我希望它接受任意数量的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;
    }
}

I tried the below and have been googling about, but man the error messages are cryptic - is what I'm trying to do even possible? 我尝试了以下,并一直在谷歌搜索,但男人的错误信息是神秘的 - 我正在努力做甚至可能吗?

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

You can do what you want, as this simple program shows: 你可以做你想做的事,因为这个简单的程序显示:

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

The thing is, that once RunSafeFn2 is a template, you may as well also template the functor itself. 问题是,一旦RunSafeFn2成为模板,您也可以RunSafeFn2函数本身。 There's very little benefit to type erasing the callable when you are already a template. 当您已经是模板时,键入擦除可调用的内容几乎没有什么好处。 So in practice, it just makes more sense to do: 所以在实践中,它更有意义:

template <class F, class ... Ts>
void foo(F f, Ts && ... ts) {
    f(std::forward<Ts>(ts)...);
}

Which still allows the usage above, but also allows doing: 哪个仍然允许上面的用法,但也允许做:

foo([] (int i) { std::cerr << "hello " << i; }, 5);

Which will also be more efficient since you completely avoid creating a std::function object. 由于完全避免创建std::function对象,因此效率也会更高。 To handle the return type, since you're limited to C++11, you could do: 要处理返回类型,因为你只限于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)...);
    }
    ...
}

Edit: let me add one final thought: In C++11 and on, where callables are so easy to create, a much simpler alternative to this is actually to take a callable and no arguments: 编辑:让我添加一个最后的想法:在C ++ 11及其中,callables很容易创建,更简单的替代方法实际上是采用可调用且参数:

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

That's because it's pretty easy to capture around the arguments that you need. 那是因为很容易捕捉到你需要的论据。 For example, if I had written my original example that way, I could use it by doing: 例如,如果我以这种方式编写了我的原始示例,我可以通过执行以下操作来使用它:

int i = 5;
foo([&] () { std::cerr << "hello " << i; });

This has pros and cons especially perhaps when dealing with move only types, but if you want to minimize maintenance burden and your use cases are simple, this is a reasonable alternative. 这有利有弊,特别是在处理移动类型时,但如果您想最大限度地减少维护负担并且您的用例很简单,这是一个合理的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM