I've written a traits class that lets me extract information about the arguments and type of a function or function object in C++0x (tested with gcc 4.5.0). The general case handles function objects:
template <typename F> struct function_traits { template <typename R, typename... A> struct _internal { }; template <typename R, typename... A> struct _internal<R (F::*)(A...)> { // ... }; typedef typename _internal<decltype(&F::operator())>::<<nested types go here>>; };
Then I have a specialization for plain functions at global scope:
template <typename R, typename... A> struct function_traits<R (*)(A...)> { // ... };
This works fine, I can pass a function into the template or a function object and it works properly:
template <typename F> void foo(F f) { typename function_traits<F>::whatever ...; } int f(int x) { ... } foo(f);
What if, instead of passing a function or function object into foo
, I want to pass a lambda expression?
foo([](int x) { ... });
The problem here is that neither specialization of function_traits<>
applies. The C++0x draft says that the type of the expression is a "unique, unnamed, non-union class type". Demangling the result of calling typeid(...).name()
on the expression gives me what appears to be gcc's internal naming convention for the lambda, main::{lambda(int)#1}
, not something that syntactically represents a C++ typename.
In short, is there anything I can put into the template here:
template <typename R, typename... A> struct function_traits<????> { ... }
that will allow this traits class to accept a lambda expression?
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.
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.
Significance of Lambda Function in C/C++ Lambda Function − Lambda are functions is an inline function that doesn't require any implementation outside the scope of the main program. Lambda Functions can also be used as a value by the variable to store.
I think it is possible to specialize traits for lambdas and do pattern matching on the signature of the unnamed functor. Here is the code that works on g++ 4.5. Although it works, the pattern matching on lambda appears to be working contrary to the intuition. I've comments inline.
struct X { float operator () (float i) { return i*2; } // If the following is enabled, program fails to compile // mostly because of ambiguity reasons. //double operator () (float i, double d) { return d*f; } }; template <typename T> struct function_traits // matches when T=X or T=lambda // As expected, lambda creates a "unique, unnamed, non-union class type" // so it matches here { // Here is what you are looking for. The type of the member operator() // of the lambda is taken and mapped again on function_traits. typedef typename function_traits<decltype(&T::operator())>::return_type return_type; }; // matches for X::operator() but not of lambda::operator() template <typename R, typename C, typename... A> struct function_traits<R (C::*)(A...)> { typedef R return_type; }; // I initially thought the above defined member function specialization of // the trait will match lambdas::operator() because a lambda is a functor. // It does not, however. Instead, it matches the one below. // I wonder why? implementation defined? template <typename R, typename... A> struct function_traits<R (*)(A...)> // matches for lambda::operator() { typedef R return_type; }; template <typename F> typename function_traits<F>::return_type foo(F f) { return f(10); } template <typename F> typename function_traits<F>::return_type bar(F f) { return f(5.0f, 100, 0.34); } int f(int x) { return x + x; } int main(void) { foo(f); foo(X()); bar([](float f, int l, double d){ return f+l+d; }); }
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