GCC は準拠していないと思います。N3092 §5.1.2/5 は言う
ラムダ式のクロージャー型には、パブリック インライン関数呼び出し演算子 (13.5.4) があり、そのパラメーターと戻り値の型は、ラムダ式の parameter-declaration-clause と Trailing-return-type によってそれぞれ記述されます。この関数呼び出し演算子は、ラムダ式の parameter-declaration-clause の後に mutable が続かない場合に限り、const (9.3.1) と宣言されます。
そのため、クロージャー オブジェクトの型に関する多くのことは実装定義ですが、関数自体は であるためにはメンバーであるpublic
必要があり、 であるためには非静的メンバーである必要がありますconst
。
編集:このプログラムはoperator()
、それが GCC 4.6 のメンバー関数であることを示しています。これは本質的に 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;
}
出力:
member of Z4mainEUlvE_, returns i takes i
編集:唯一の問題は、特定のクロージャー呼び出し演算子へのポインターが ptmf テンプレート パターンと一致しないことです。回避策は、ラムダ式を宣言することmutable
です。これは、キャプチャがなく、(問題の修正は別として) 呼び出し演算子の const-ness を変更するだけの場合は無意味です。
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;
出力:
returns i takes i
member of Z4mainEUliE0_ , returns i takes i
member of Z4mainEUliE0_ , returns i takes i
mutable がなく、constspectfun
がある場合、最後の 2 つのクエリのいずれの署名も出力しません。