如何制作一个函数模板,该模板接受带有可变参数的函子

How to make a function template that takes a functor with variable arguments

本文关键字:变参 参数 何制作 一个 函数模板      更新时间:2023-10-16

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

奇怪的是,如果我给它传递一个function对象,我就可以调用passn

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中可能吗?

您可以使用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);
}

(演示)

它假设您传入一个具有operator()的类型。它获取该函数的地址,并从该成员指针推导参数。

如果您向函数传递一个具有多个operator()的对象,该函数将失败,因为这样获取其地址将是不明确的,但lambdas不会产生该问题。