I'm trying to implement a function template (in C++11) whose parameter is a lambda with arbitrary parameters, and return a compatible std::function object. The goal is for the returned function when called to invoke the original lambda asynchronously, but for now I'm just returning the original lambda.
The problem is simply getting the compiler to accept a lambda as the parameter of the function template. Here are some simple templates:
#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;
}
They do the same thing, it's just that pass1
only works on single-parameter functors while passn
takes an arbitrary number.
So now we try using them, first pass1
:
auto p1 = pass1( [](int a)->void {cout << a;} ); // ERROR
This doesn't work; the compiler can't seem to tell what parameters the lambda takes. Clang error message is:
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) {
I can work around this by explicitly specifying the template parameter type:
auto p2 = pass1<int>( [](int a)->void {cout << a;} ); // OK
However, this workaround fails with 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) {
^
The weird thing is that I can invoke passn
if I pass it a function
object:
function<void(int)> fn = [](int a)->void {cout << a;};
auto x = passn<int>(fn); // OK
...in fact, I don't even have to specify the template parameter type:
auto y = passn(fn); // OK
The function I actually need is going to be like passn
, but I don't want the extra verbiage of having to wrap a function
object around the lambda every time I call it. Am I missing something, or is this just not possible? Would it be possible in C++14?
When an argument of a data type is passed to functionName (), the compiler generates a new version of functionName () for the given data type. Once we've declared and defined a function template, we can call it in other functions or templates (such as the main () function) with the following syntax
Defining a Function Template A function template starts with the keyword template followed by template parameter (s) inside <> which is followed by the function definition. template <typename T> T functionName(T parameter1, T parameter2,...) { // code }
So basically, Variadic function templates are functions that can take multiple numbers of arguments. template (typename arg, typename... args) return_type function_name (arg var1, args... var2) Note: The arguments must be put inside angular brackets.
The family of functions is an example of functions that use variable argument lists. printf argument-declaration-list To access arguments after those declared, use the macros contained in the standard include file <stdarg.h> as described below.
You can use this implementation of 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)
It assumes you pass in a type that has an operator()
. It takes the address of that function and deduces parameters from that member pointer.
The function will fail if you pass it an object that has multiple operator()
s because then taking its address will be ambiguous, but lambdas will not produce that problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With