overload operator equal assignment c++ c++11 lambda operator-overloading language-lawyer

equal - function operator c++



Un lambda positivo: ''+[]{}''-¿Qué brujería es esta? (1)

En la pregunta de desbordamiento de pila. Redefinir lambdas no permitidas en C ++ 11, ¿por qué? , se dio un pequeño programa que no compila:

int main() { auto test = []{}; test = []{}; }

La pregunta fue respondida y todo parecía estar bien. Luego vino Johannes Schaub e hizo una observación interesante :

Si pones un + antes de la primera lambda, mágicamente comienza a funcionar.

Así que tengo curiosidad: ¿Por qué funciona lo siguiente?

int main() { auto test = +[]{}; // Note the unary operator + before the lambda test = []{}; }

Se compila bien con GCC 4.7+ y Clang 3.2+. ¿El código es conforme?


Sí, el código es estándar conforme. El + activa una conversión a un puntero de función simple anterior para lambda.

Lo que pasa es esto:

El compilador ve el primer lambda ( []{} ) y genera un objeto de cierre de acuerdo con §5.1.2. Como la lambda es una lambda que no captura , se aplica lo siguiente:

5.1.2 Expresiones de Lambda [expr.prim.lambda]

6 El tipo de cierre para una expresión lambda sin captura lambda tiene una función de conversión const no explícita no virtual pública para apuntar a la función que tiene los mismos parámetros y tipos de retorno que el operador de llamada a función del tipo de cierre. El valor devuelto por esta función de conversión será la dirección de una función que, cuando se invoca, tiene el mismo efecto que invocar al operador de llamada a función del tipo de cierre.

Esto es importante ya que el operador unario + tiene un conjunto de sobrecargas integradas, específicamente este:

13.6 Operadores incorporados [over.built]

8 Para cada tipo T existen funciones de operador candidato de la forma.

T* operator+(T*);

Y con esto, queda bastante claro lo que sucede: cuando se aplica operator + al objeto de cierre, el conjunto de candidatos integrados sobrecargados contiene un puntero de conversión a cualquier y el tipo de cierre contiene exactamente un candidato: la conversión a Función puntero de la lambda.

El tipo de test en test auto test = +[]{}; Por lo tanto, se deduce al void(*)() . Ahora la segunda línea es fácil: para el segundo objeto lambda / cierre, una asignación al puntero de función desencadena la misma conversión que en la primera línea. Aunque la segunda lambda tiene un tipo de cierre diferente, el puntero a la función resultante es, por supuesto, compatible y puede asignarse.