c++ - namespace - std::string
Operador de llamadas con el tipo de retorno automático elegido en lugar del constructor cuando se usa la función std:: (1)
El siguiente fragmento de código:
#include <functional>
struct X {
X(std::function<double(double)> fn); // (1)
X(double, double); // (2)
template <class T>
auto operator()(T const& t) const { // (3)
return t.foo();
}
};
int main() {
double a, b;
auto x = X(a, b);
return 0;
}
... no se compila con el clang
(4.0.1) y g++
(6.3, 7.2) cuando se usa -std=c++14
- probado en OSX y godbolt.org .
Pero se compila sin problema si:
- Quito constructor
(1)
; - o establezco el tipo de retorno a un tipo concreto (por ejemplo,
double
) en(3)
; - o si uso un tipo de retorno final (
-> decltype(t.foo())
) en(3)
; - compilar usando
-std=c++1z
(gracias @bolov).
Quizás haya algo obvio que me esté perdiendo aquí ... ¿Hay algún problema con este código? ¿Es esto un error?
Estás copiando inicializando x
. Y X
es un tipo difícil por las siguientes razones:
Se puede construir a partir de cualquier objeto invocable que se pueda llamar con un argumento doble. Y cuyo tipo de devolución es convertible a doble.
Es un objeto llamable que puede llamarse con un argumento doble. Pero el tipo de retorno necesita deducirse.
Hay un compilador generado copia constructor para
X
La ambigüedad está empezando a ser evidente aquí, espero. Hay necesidad de resolución de sobrecarga.
Cuando eliminas el primer c''tor, se elimina la ambigüedad de una manera obvia. El caso interesante es el operador de llamada de función.
Verá, la std::function
solo se puede construir a partir de la llamada que se pasa (el operador con plantilla solo participará en la resolución de sobrecarga) si las conversiones entre argumentos a parámetros y entre tipos de retorno son posibles. Todo esto se hace en un contexto no evaluado, por lo que el operador de llamada de función con plantilla no se usa odr, y por lo tanto no se crea una instancia.
Cuando el tipo de retorno es un tipo de marcador de posición, el std::function
c''tor no puede resolverse fácilmente si se debe construir o no. La compilación falla durante la resolución de sobrecarga, aunque si hubiera tenido éxito, se habría seleccionado el copiador de X
Como @VTT sugirió en un comentario, marcar el indicador que acepta una std::function
como explícita también resolverá la ambigüedad. Todo a causa del compilador que no tiene que clasificar la secuencia de conversión implícita en absoluto.