I believe that GCC is noncompliant. N3092 §5.1.2/5 says
The closure type for a
lambda-expression has a public inline
function call operator (13.5.4) whose
param- eters and return type are
described by the lambda-expression’s
parameter-declaration-clause and
trailing- return-type respectively.
This function call operator is
declared const (9.3.1) if and only if
the lambda- expression’s
parameter-declaration-clause is not
followed by mutable.
So while many things about the closure object's type are implementation-defined, the function itself must be a member to be public and must be a nonstatic member to be const.
EDIT: This program indicates that operator() is a member function on GCC 4.6, which is essentially the same as 4.5.
#include <iostream>
#include <typeinfo>
using namespace std;
template< class ... > struct print_types {};
template<> struct print_types<> {
friend ostream &operator<< ( ostream &lhs, print_types const &rhs ) {
return lhs;
}
};
template< class H, class ... T > struct print_types<H, T...> {
friend ostream &operator<< ( ostream &lhs, print_types const &rhs ) {
lhs << typeid(H).name() << " " << print_types<T...>();
return lhs;
}
};
template< class T >
struct spectfun {
friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {
lhs << "unknown";
return lhs;
}
};
template< class R, class ... A >
struct spectfun< R (*)( A ... ) > {
friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {
lhs << "returns " << print_types<R>()
<< " takes " << print_types<A ...>();
return lhs;
}
};
template< class C, class R, class ... A >
struct spectfun< R (C::*)( A ... ) > {
friend ostream &operator<< ( ostream &lhs, spectfun const &rhs ) {
lhs << "member of " << print_types<C>() << ", " << spectfun<R (*)(A...)>();
return lhs;
}
};
template< class T >
struct getcall {
typedef decltype(&T::operator()) type;
};
int main() {
int counter = 0;
auto count = [=]( int ) mutable { return ++ counter; };
cerr << spectfun< getcall<decltype(count)>::type >() << endl;
}
output:
member of Z4mainEUlvE_, returns i takes i
EDIT: It looks like the only problem is that pointers to certain closure call operators fail to match ptmf template patterns. The workaround is to declare the lambda expression mutable. This is meaningless if there is no capture and only (aside from fixing the problem) seems to change the const-ness of the call operator.
template< class T >
struct getcall {
typedef decltype(&T::operator()) type;
static type const value;
};
template< class T >
typename getcall<T>::type const getcall<T>::value = &T::operator();
int main() {
auto id = []( int x ) mutable { return x; };
int (*idp)( int ) = id;
typedef decltype(id) idt;
int (idt::*idptmf)( int ) /* const */ = getcall< decltype(id) >::value;
cerr << spectfun< decltype(idp) >() << endl;
cerr << spectfun< decltype(idptmf) >() << endl;
cerr << spectfun< getcall<decltype(id)>::type >() << endl;
output:
returns i takes i
member of Z4mainEUliE0_ , returns i takes i
member of Z4mainEUliE0_ , returns i takes i
Without the mutable and with the const, spectfun does not print signatures for either of the last two queries.