How has the functor below to be altered to work as a lambda wrapper?
template<typename T>
class F {
T f;
public:
F(T t){
f = t;
}
T& operator()(){
return f;
}
};
int main()
{
int x = 5;
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
return 0;
}
The compiler says
error: no matching function for call to 'F<int (*)(int, int)>::F(main()::<lambda(int, int)>)'
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
Lambda-expressions are not allowed in unevaluated expressions, template arguments, alias declarations, typedef declarations, and anywhere in a function (or function template) declaration except the function body and the function's default arguments.
We have seen that lambda is just a convenient way to write a functor, therefore we should always think about it as a functor when coding in C++. We should use lambdas where we can improve the readability of and simplify our code such as when writing callback functions.
Functors allow to write functional programs in C++. Lambdas are syntactic sugar to simplify this.
Passing Lambda Expressions as Arguments You can pass lambda expressions as arguments to a function. If you have to pass a lambda expression as a parameter, the parameter type should be able to hold it. If you pass an integer as an argument to a function, you must have an int or Integer parameter.
It's more complicated... Internally lambda functions that capture variables are not functions as such, are data structures. I not found any solution developed and many requests and questions unresolved, then I developed this minimal code to wrap lambda pointer not using std::function or any other standard function or dependence. Pure c++11.
Accepts all kinds of lambda captures, arguments by reference, return void, and supports top level functions and member methods.
// Type checkers
template<typename _Type>
struct IsVoid
{
static const bool value = false;
};
template<>
struct IsVoid<void>
{
static const bool value = true;
};
// Callable signature interfce
template<typename _ReturnType, typename..._ArgTypes>
struct Callable
{
typedef _ReturnType ReturnType;
typedef _ReturnType (*SignatureType)(_ArgTypes...);
virtual _ReturnType operator()(_ArgTypes...args) = 0;
};
// Function and lambda closure wrapper
template<typename _ClosureType, typename _ReturnType, typename..._ArgTypes>
struct Closure: public Callable<_ReturnType, _ArgTypes...>
{
typedef _ClosureType ClosureType;
const _ClosureType closureHandler;
Closure(const _ClosureType& handler)
: closureHandler(handler)
{
}
_ReturnType operator()(_ArgTypes...args) override
{
if(IsVoid<_ReturnType>::value)
closureHandler(args...);
else
return closureHandler(args...);
}
};
// Fuction template selector
template <typename _FunctionType>
class Function
: public Function<decltype(&_FunctionType::operator())>
{
};
// Function, lambda, functor...
template <typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(*)(_ArgTypes...)> SelfType;
typedef _ReturnType(*SignatureType)(_ArgTypes...);
Callable<_ReturnType, _ArgTypes...>* callableClosure;
Function(_ReturnType(*function)(_ArgTypes...))
: callableClosure(new Closure<SignatureType, _ReturnType, _ArgTypes...>(function))
{
}
// Captured lambda specialization
template<typename _ClosureType>
Function(const _ClosureType& function)
: callableClosure(new Closure<decltype(function), _ReturnType, _ArgTypes...>(function))
{
}
_ReturnType operator()(_ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(*callableClosure)(args...);
else
return (*callableClosure)(args...);
}
};
// Member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...)> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...);
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...))
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
// Const member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...) const>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...) const> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...) const;
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...) const)
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
Tests:
#include <iostream>
class Foo
{
public:
int bar(int a, int b)
{
return a + b;
}
};
int someFunction(int a, int b)
{
return a + b;
}
int main(int argc, char** argv)
{
int a = 10;
int b = 1;
// Lambda without capturing
Function<int(*)(int)> fn1([] (int b) -> int {
return b;
});
std::cout << fn1(2) << std::endl; // 2
// Lambda capturing variable
Function<int(*)(int)> fn2([a] (int c) -> int {
return a + c;
});
std::cout << fn2(-7) << std::endl; // 3
// Lambda capturing scope
Function<int(*)(int)> fn3([&] (int c) -> int {
return a + c;
});
std::cout << fn3(-5) << std::endl; // 5
// Arguments by reference
Function<void(*)(int&, int)> fn4([] (int& d, int f) {
d = d + f;
});
fn4(a, -3); // Void call
std::cout << a << std::endl; // 7
// Top level function reference
Function<int(*)(int, int)> fn6(someFunction);
std::cout << fn6(a, 4) << std::endl; // 11
// Member method
Foo* foo = new Foo();
Function<int(Foo::*)(int,int)> fn7(foo->bar);
std::cout << fn7(foo, a, 8) << std::endl; // 15
}
Works correctly wih gcc 4.9.
Thanks for your question.
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