如何创建一个带有可变参数的仿函数的函数模板

Jen*_*fke 8 c++ lambda templates c++11

我正在尝试实现一个函数模板(在C++ 11中),其参数是一个带有任意参数的lambda,并返回一个兼容的std :: function对象.当被调用以异步调用原始lambda时,目标是返回函数,但是现在我只返回原始lambda.

问题只是让编译器接受lambda作为函数模板的参数.以下是一些简单的模板:

#include <functional>
using namespace std;

template <class Arg>
function<void(Arg)> pass1(function<void(Arg)> fn) {
    return fn;
}

template <class... Args>
function<void(Args...)> passn(function<void(Args...)> fn) {
    return fn;
}
Run Code Online (Sandbox Code Playgroud)

它们做同样的事情,它只是pass1在单参数仿函数上工作,同时passn取任意数.

所以现在我们尝试使用它们,首先pass1:

    auto p1 = pass1( [](int a)->void {cout << a;} );  // ERROR
Run Code Online (Sandbox Code Playgroud)

这不起作用; 编译器似乎无法告诉lambda采用什么参数.Clang错误消息是:

Untitled.cpp:17:12: error: no matching function for call to 'pass1'
    auto p1 = pass1( [](int a)->void {cout << a;} );
              ^~~~~
Untitled.cpp:6:21: note: candidate template ignored: could not match 'function<void (type-parameter-0-0)>' against '(lambda at Untitled.cpp:17:19)'
function<void(Arg)> pass1(function<void(Arg)> fn) {
Run Code Online (Sandbox Code Playgroud)

我可以通过显式指定模板参数类型来解决这个问题:

    auto p2 = pass1<int>( [](int a)->void {cout << a;} );  // OK
Run Code Online (Sandbox Code Playgroud)

但是,此解决方法失败了passn:

    auto p3 = passn<int>( [](int a)->void {cout << a;} );

Untitled.cpp:23:12: error: no matching function for call to 'passn'
    auto p3 = passn<int>( [](int a)->void {cout << a;} );
              ^~~~~~~~~~
Untitled.cpp:11:25: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against '(lambda at Untitled.cpp:23:24)'
function<void(Args...)> passn(function<void(Args...)> fn) {
                    ^
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我传递一个对象,我可以调用passnfunction:

    function<void(int)> fn = [](int a)->void {cout << a;};
    auto x = passn<int>(fn);  // OK
Run Code Online (Sandbox Code Playgroud)

...实际上,我甚至不必指定模板参数类型:

    auto y = passn(fn);  // OK
Run Code Online (Sandbox Code Playgroud)

我实际需要的功能就像是passn,但我不希望function每次调用它时都必须在lambda周围包装一个对象.我错过了什么,或者这是不可能的?在C++ 14中会有可能吗?

nwp*_*nwp 6

你可以使用这个实现passn:

#include <functional>
#include <iostream>

template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...) const);

template <class RetVal, class T, class... Args>
std::function<RetVal(Args...)> get_fun_type(RetVal (T::*)(Args...));

template <class T>
auto passn(T t) -> decltype(get_fun_type(&T::operator())) {
    return t;
}

int main() {
    auto fun = passn([](int a) { std::cout << a; });
    fun(42);
}
Run Code Online (Sandbox Code Playgroud)

(演示)

它假设您传入的类型有operator().它获取该函数的地址并从该成员指针中推导出参数.

如果你传递一个有多个operator()s 的对象,该函数将失败,因为然后取其地址将是不明确的,但lambdas不会产生该问题.