c++11 lambda overloading

c++11 - Resolución de sobrecarga ambigua en el puntero de función y función std:: para una lambda usando+



overloading (1)

El + en la expresión +[](){} es el operador unario + . Se define de la siguiente manera en [expr.unary.op] / 7:

El operando del operador unario + tendrá una enumeración aritmética, sin ámbito o tipo de puntero y el resultado es el valor del argumento.

La lambda no es de tipo aritmético, etc., pero se puede convertir:

[expr.prim.lambda] / 3

El tipo de lambda-expression [...] es un tipo de clase no sindicalizado sin nombre único, denominado tipo de cierre , cuyas propiedades se describen a continuación.

[expr.prim.lambda] / 6

El tipo de cierre para una expresión lambda sin captura lambda tiene una función public no virtual no virtual conversión de const para señalar a la función que tiene el mismo parámetro y tipos de retorno que el operador de llamada de 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 de función del tipo de cierre.

Por lo tanto, el unario + fuerza la conversión al tipo de puntero a función, que es para este void (*)() lambda void (*)() . Por lo tanto, el tipo de expresión +[](){} es este tipo de puntero a función void (*)() .

La segunda sobrecarga void foo(void (*f)()) convierte en una coincidencia exacta en la clasificación de resolución de sobrecarga y, por lo tanto, se elige inequívocamente (ya que la primera sobrecarga NO es una coincidencia exacta).

El lambda [](){} se puede convertir a std::function<void()> mediante el ctor de plantilla no explícito de std::function , que toma cualquier tipo que cumpla los requisitos de Callable y CopyConstructible .

La lambda también se puede convertir en void (*)() través de la función de conversión del tipo de cierre (ver arriba).

Ambas son secuencias de conversión definidas por el usuario y del mismo rango. Es por eso que la resolución de sobrecarga falla en el primer ejemplo debido a la ambigüedad.

Según Cassio Neri, respaldado por un argumento de Daniel Krügler, este truco unario debe ser un comportamiento específico, es decir, puedes confiar en él (ver discusión en los comentarios).

Aún así, recomendaría usar un molde explícito para el tipo de puntero de función si quiere evitar la ambigüedad: no necesita preguntar en SO qué es y por qué funciona;)

En el siguiente código, la primera llamada a foo es ambigua y, por lo tanto, no se puede compilar.

El segundo, con el agregado + antes de la lambda, resuelve la sobrecarga del puntero a la función.

#include <functional> void foo(std::function<void()> f) { f(); } void foo(void (*f)()) { f(); } int main () { foo( [](){} ); // ambiguous foo( +[](){} ); // not ambiguous (calls the function pointer overload) }

¿Qué está haciendo la notación + aquí?