Я считаю, что GCC не соответствует требованиям. N3092 §5.1.2 / 5 говорит
Тип закрытия для
лямбда-выражение имеет публичный встроенный
оператор вызова функции (13.5.4), чей
параметры и тип возвращаемого значения
описывается лямбда-выражением
параметр-объявление-предложение и
трейлинг-возврат-тип соответственно.
Этот оператор вызова функции
объявлен 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
. Это бессмысленно, если нет захвата, и только (не считая исправления проблемы), по-видимому, изменяет постоянство оператора вызова.
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
Без переменной и с const, spectfun
не печатает подписи ни для одного из последних двух запросов.