expresiones - std c++
¿Por qué se compila esto cuando se pasa un lambda en la inicialización y asignación directas pero no con la inicialización de la copia? (2)
¿Por qué el operador de asignación no permite una expresión lambda cuando se realiza en la misma línea en que se declara el objeto?
Aunque parece estar funcionando en MSVC.
Pruebe el código: https://godbolt.org/g/n2Tih1
class Func
{
typedef void(*func_type)();
func_type m_f;
public:
Func() {}
Func(func_type f) : m_f(f) {}
Func operator=(func_type f) {
m_f = f;
return *this;
}
};
int main()
{
// doesn''t compile in GCC and clang, it does in MSVC
Func f1 = []() {
};
// compiles!
Func f2;
f2 = []() {
};
// compiles!
Func f3([]() {
});
}
Su primer caso involucra dos conversiones implícitas, lambda a void(*)()
luego void(*)()
a Func
. Puedes tener como máximo 1 conversión implícita.
Si puedes eliminar una de las conversiones implícitas, debería funcionar bien. Aquí hay algunas soluciones potenciales que puedes probar:
// Explicit cast to a function pointer
Func f1 = static_cast<void(*)()>([]() {});
// func_ptr is already a function pointer
// eliminating one of the implcit conversions
void (*func_ptr)() = [](){};
Func f2 = func_ptr;
// The conversion from `void(*)()` is no longer implicit
Func f3{ [](){} };
Func f1 = []() {};
es la inicialización de la copia , que requiere dos conversiones implícitas definidas por el usuario para construir f1
, la primera es desde el lambda al puntero de la función, la segunda es desde el puntero a la función hasta la función. Solo se permite una conversión implícita definida por el usuario en una secuencia de conversión, por lo que falla.
(énfasis mío)
Si T es un tipo de clase, y la versión no calificada por cv del tipo de otro no es T o se deriva de T, o si T no es de tipo clase, pero el tipo de otro es un tipo de clase, secuencias de conversión definidas por el usuario se puede convertir el tipo de otro a T (o a un tipo derivado de T si T es un tipo de clase y está disponible una función de conversión) y se selecciona el mejor a través de la resolución de sobrecarga.
y
La secuencia de conversión implícita consta de lo siguiente, en este orden:
1) cero o una secuencia de conversión estándar;
2) cero o una conversión definida por el usuario;
3) cero o una secuencia de conversión estándar.
Para f2 = []() {};
se intenta llamar al operador de asignación apropiado, Func
tiene uno y espera que la función apunte como argumento; solo se requiere una conversión implícita de la lambda a puntero de función y luego funciona bien.
Func f3([]() {});
Es la inicialización directa , se intenta llamar al constructor apropiado, Func
tiene uno y espera el puntero a la función como argumento. Entonces es lo mismo que f2
.
Puede obtener el punto de la diferencia entre la inicialización de la copia y la inicialización directa.
Además, la conversión implícita en la inicialización de la copia debe producir T directamente desde el inicializador, mientras que, por ejemplo, la inicialización directa espera una conversión implícita del inicializador a un argumento del constructor de T.