我正在尝试实现一个函数模板(在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中使用?
答案 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不会产生这个问题。