2012-07-10 16 views
6

Considere el siguiente código:La captura lambda causa un error de tipos de operandos incompatibles?

main() 
{ 
    bool t; 
    ... 
    std::function<bool (bool)> f = t ? [](bool b) { return b; } : [](bool b) { return !b; }; // OK 
    std::function<bool (bool)> f = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error 
} 

cuando se compila con Clang 3.1, la asignación de la no captura de lambda funciona mientras el uno con capturas falla:

main.cpp:12:36: error: incompatible operand types ('<lambda at main.cpp:12:38>' and '<lambda at main.cpp:12:71>') 
     std::function<bool (bool)> f2 = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

¿Por qué la captura de la misma variable hace que el 2 lambdas para ser de tipos incompatibles?

Respuesta

12

El tipo de lambda es "un tipo de clase único, sin unión" llamado tipo de cierre. Cada lambda se implementa como un tipo diferente, local al alcance de la declaración, que tiene un operador sobrecargado() para llamar al cuerpo de la función.

Ejemplo: si se escribe esto:

auto a=[t](bool b){return t==b;}; 
auto b=[t](bool b){return t!=b;}; 

A continuación, el compilador compila esto (más o menos):

class unique_lambda_name_1 
{ 
bool t; 
public: 
unique_lambda_name_1(bool t_) t(_t) {} 
bool operator() (bool b) const { return t==b; } 
} a(t); 
class unique_lambda_name_2 
{ 
bool t; 
public: 
unique_lambda_name_2(bool t_) t(_t) {} 
bool operator() (bool b) const { return t!=b; } 
} b(t); 

A y B tienen diferentes tipos y no se puede utilizar en el operador?:

Sin embargo, el §5.1.2 (6) dice que el tipo de cierre de una lambda sin captura tiene un operador público de conversión no explícito, que convierte la lambda en un puntero de función. Pueden implementarse cierres como funciones simples. Cualquier lambda con el mismo argumento y los mismos tipos de devolución se pueden convertir al mismo tipo de puntero y, por lo tanto, se puede aplicar el operador ternario?: A ellos.

Ejemplo: la lambda no captura:

auto c=[](bool b){return b;}; 

se implementa como esto:

class unique_lambda_name_3 
{ 
static bool body(bool b) { return b; } 
public: 
bool operator() (bool b) const { return body(b); } 
operator decltype(&body)() const { return &body; } 
} c; 

lo que significa que esta línea:

auto x = t?[](bool b){return b;}:[](bool b){return !b;}; 

significa en realidad esto:

// a typedef to make this more readable 
typedef bool (*pfun_t)(bool); 
pfun_t x = t?((pfun_t)[](bool b){return b;}):(pfun_t)([](bool b){return !b;}); 
+0

Gracias por la explicación detallada. No sabía que se implementan de manera diferente. Tiene sentido ahora. –

Cuestiones relacionadas