如何使用variadic模板使用std :: function

时间:2018-05-05 14:56:22

标签: c++ stl

有一个template for constructing std::function:

template< class R, class... Args >
class function<R(Args...)>;

我还没弄明白如何调用它。 (VC ++,如果重要的话。)

问题:如何在不使用std::function的情况下将std::bind与可变参数列表一起使用?

#include <functional>
#include <iostream>
using vfunc = std::function<void()>;
using namespace std; // I know, I know.

template<class F, class... Args>
void
run(F&& f, Args&&... args) {
    vfunc fn = bind(forward<F>(f), forward<Args>(args)...); //OK
    //vfunc fn = vfunc(forward<F>(f), forward<Args>(args)...); // COMPILER ERROR
    fn();
}

void foo(int x) {
    cout << x << " skidoo\n";
}
int main() {
    run(foo, 23);
    return 0;
}

2 个答案:

答案 0 :(得分:2)

  

有一个用于构建std::function的模板。

template< class R, class... Args >
class function<R(Args...)>;

这不是宣言的意思。它没有声明构造函数或“构造”任何东西的模板;它是模板类std::function的特化。专门化是std :: function的唯一定义;永远不会定义基本模板。我认为这与在模板声明中使用函数签名有关。也就是说,能够通过函数而不是函数来使用模板。

您希望获取可调用对象和一些值,并创建一个新的可调用对象来存储这些值,这些值具有operator()重载,可以使用这些值调用给定函数。 std::function不这样做;它没有这样做的构造函数。

完全 std::bind的用途。基本上,您的代码很好:将bind的结果存储在function内是完全有效的。

答案 1 :(得分:0)

在这种情况下,您可以将函数包装在lambda中并从中构造std::function

template<class F, class... Args>
void run(F&& f, Args&&... args) {
    auto fn = vfunc{
        [=]() mutable {
            std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
        }
    };

    fn(); // fn is of type std::function<void()>
}

我使lambda变得可变,因此std::forward不会默默地移动。

但请注意,[=]捕获将复制所有内容。要支持仅移动类型,可以使用元组:

[f = std::forward<F>(f), args = std::tuple{std::forward<Args>(args)...}]() mutable {
    std::apply(std::forward<F>(f), std::move(args));
}

在C ++ 20中,这变得更容易:

[f = std::forward<F>(f), ...args = std::forward<Args>(args)...]() mutable {
    std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}