如何制作一个带有可变参数的仿函数的函数模板

时间:2017-02-08 22:30:56

标签: c++ c++11 templates lambda

我正在尝试实现一个函数模板(在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;
}

他们做同样的事情,只是pass1仅适用于单参数仿函数,而passn采用任意数字。

现在我们尝试使用它们,首先是pass1

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

这不起作用;编译器似乎无法告诉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) {

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

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

但是,此解决方法因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) {
                    ^

奇怪的是,如果我传递passn对象,可以调用function

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

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

    auto y = passn(fn);  // OK

我实际需要的函数就像passn一样,但我不希望每次调用它时都必须在lambda周围包裹一个function对象。我错过了什么,或者这是不可能的?是否可以在C ++ 14中使用?

1 个答案:

答案 0 :(得分: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);
}

demo

它假设您传入的文件类型为operator()。它接受该函数的地址并从该成员指针中推导出参数。

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