2011-01-11 14 views
9

Tengo una pregunta sobre C++ 0x lambdas. En mi código, sería beneficioso saber si un tipo determinado es del tipo de una expresión lambda de C++ 0x. Para dar un ejemplo:¿Es un rasgo de C++ is_lambda, puramente implementado como una biblioteca, imposible?

struct foobar 
{ 
    void operator()() 
    { 
    } 
}; 

auto lambda = []{}; 
typedef is_lambda < decltype(lambda) > ::type T; // T would be a true_type 
typedef is_lambda <foobar> ::type T; // T would be a false_type 

Es bastante fácil distinguir las expresiones lambda de los tipos de función y miembro. Los funtores son otra cosa.

El problema que veo aquí es la definición de expresiones lambda según el próximo estándar C++ 0x; lo único que debe definirse es un operador de llamada pública. Sin embargo, esto también es cierto para un funtor; la prueba de la presencia del operador de llamada no es suficiente para distinguir las expresiones lambda de los funtores. Además, si el operador de un funtor es no presente, se producirá un error del compilador, ya que SFINAE no se aplica. ¿Cuándo sucede esto? El operador de llamada del operador puede ser modelado. Así, dicho código:

typedef decltype(&T::operator()) call_type; 

va a trabajar para ambas expresiones lambda y funtores con operador de llamada no moldeado, y generar un error de compilación para los operadores de llamadas con plantilla.

Creo que un rasgo is_lambda < > solo se puede crear utilizando las características del compilador intrínseco. ¿Ves una forma de implementar este rasgo?

+3

Me pregunto para qué la usarías? –

+0

Perdón por la respuesta tardía. Sí, creo que cometí un error lógico. No tiene sentido distinguir functors regulares de lambdas; puedo ver este último como el anterior. Sin embargo, existe la necesidad de determinar si existe o no un operador de llamada. Hasta la fecha, parece que no existe una solución completamente genérica para este problema. Trataré esto en una pregunta separada pronto, junto con mis intentos. –

+0

@MaximYegorushkin: En cuanto a una diferencia motivadora: el tipo de * objeto de cierre * lo identifica de manera única. Lo mismo no es (necesariamente) verdadero para otros punteros a funciones u otros objetos funcionales. – BCS

Respuesta

8

Dado que la evaluación de lambda da como resultado la creación de un objeto de cierre, no hay ninguna diferencia tan pronto como el objeto pasa a una función o se copia. Y, francamente, no puedo imaginarme un problema que requiera saber si un objeto proviene de lambda.

Editar. Un estándar incluso tiene una nota en 5.1.2/2:

Nota: un objeto de cierre se comporta como un objeto función de nota (20.8) .- final

+0

Me imagino que podría estar dispuesto a saber si un tipo 'std :: function <...>' tiene estado o no.Sin embargo, dado que las funciones pueden usar variables "estáticas" o globales, no sería muy útil distinguir las lambdas de la mezcla. –

6

No creo que se pueda hacer, las lambdas no son en realidad algo nuevo semánticamente, solo son funcionantes generados por el compilador y por lo tanto se verán idénticos a los funtores regulares.

1

Es posible definir un código de macro que determina si una expresión es una expresión lambda (pero eso no es muy útil ya que no te dice si una expresión es de tipo lambda ).

#include <type_traits> 

template<typename T, typename U> 
struct SameType { 
    static_assert(!std::is_same<T, U>::value, "Must use Lambda"); 
    static T pass(T t) { return t; } 
}; 

template <typename T, typename U> 
T NotLambda(T t, U u) { return SameType<T, U>::pass(t); } 

#define ASSERT_LAMBDA(x) NotLambda(x,x) 

///////////////////////////////////// 

int fn() { return 0; } 

int main() { 
    auto l = []{ return 0; }; 
    return ASSERT_LAMBDA(fn)() +    // << fails 
      ASSERT_LAMBDA(l)() +    // << fails 
      ASSERT_LAMBDA([]{ return 0; })(); // << passes 
} 

Esto depende de la sección 5.1.2.3 que especifica que cada expresión lambda tiene un tipo distinto (que creo que es una propiedad única de lambdas).

+0

Tuve la misma idea. Si solo se pudiera hacer sin la macro fea, pero mientras encuentro la sintaxis de usar 'NotLambda' directamente (con una expresión lambda dos veces), para ser tolerable, un usuario podría, por supuesto, proporcionar accidentalmente dos objetos de función distintos. – user2023370

Cuestiones relacionadas