c++ - resolucion - ¿Por qué el tipo de retorno automático cambia la resolución de sobrecarga?
cambiar resolucion de pantalla windows 8 (1)
Basta con mirar esta llamada:
d.fun(foo_t{});
Usted crea un temporal (es decir, rvalue), pasándolo como argumento a la función. Ahora, ¿qué crees que sucede?
Primero intenta enlazar con el argumento
Arg&&
, ya que puede aceptar rvalue pero debido a una deducción de tipo de retorno no válida ( que de nuevo debido afoo_t
no se puede convertir enunsigned int
, debido a queb.fun(std::forward<Args>(args)...)
resulta ser una expresión no válida ), esta función se rechaza si utilizadecltype(expr)
como tipo de retorno, ya que en este caso SFINAE aparece en la imagen. Pero si usa simplementeauto
, SFINAE no aparece en la imagen y el error se clasifica como un error grave que da como resultado un error de compilación.La segunda sobrecarga que acepta el
foo_t const&
as se llama si SFINAE funciona en el primer caso.
Gracias a decltype
como tipo de retorno, C ++ 11 hizo que introducir decoradores fuera extremadamente fácil. Por ejemplo, considere esta clase:
struct base
{
void fun(unsigned) {}
};
Quiero decorarlo con características adicionales, y como lo haré varias veces con diferentes tipos de decoraciones, primero presento una clase de decorator
que simplemente envía todo a la base
. En el código real, esto se hace a través de std::shared_ptr
para que pueda eliminar las decoraciones y recuperar el objeto "desnudo", y todo está templado.
#include <utility> // std::forward
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
Perfecto reenvío y decltype
son simplemente maravillosos. En el código real, en realidad uso una macro que solo necesita el nombre de la función, todo lo demás es repetitivo.
Y luego, puedo introducir una clase derived
que agrega características a mi objeto ( derived
es impropia, de acuerdo, pero ayuda a entender que derived
es un tipo de base
, aunque no por herencia).
struct foo_t {};
struct derived : decorator
{
using decorator::fun; // I want "native" fun, and decorated fun.
void fun(const foo_t&) {}
};
int main()
{
derived d;
d.fun(foo_t{});
}
Luego vino C ++ 14, con devolución de tipo de deducción, que permite escribir cosas de una manera más simple: eliminar la parte de tipo decltype
de la función de reenvío:
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
Y luego se rompe. Sí, al menos según GCC y Clang, esto:
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
no es equivalente a esto (y el problema no es auto
vs. decltype(auto)
):
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
La resolución de sobrecarga parece ser completamente diferente y termina así:
clang++-mp-3.5 -std=c++1y main.cc
main.cc:19:18: error: no viable conversion from ''foo_t'' to ''unsigned int''
return b.fun(std::forward<Args>(args)...);
^~~~~~~~~~~~~~~~~~~~~~~~
main.cc:32:5: note: in instantiation of function template specialization
''decorator::fun<foo_t>'' requested here
d.fun(foo_t{});
^
main.cc:7:20: note: passing argument to parameter here
void fun(unsigned) {}
^
Entiendo el error: mi llamada ( d.fun(foo_t{})
) no coincide perfectamente con la firma de const foo_t&
derived::fun
, que requiere una const foo_t&
, por lo que el muy ansioso decorator::fun
entra en acción (sabemos cómo Args&&...
es extremadamente impaciente por unirse a cualquier cosa que no coincida perfectamente). Así que reenvía esto a la base::fun
que no puede manejar foo_t
.
Si cambio derived::fun
para tomar foo_t
lugar de const foo_t&
, entonces funciona como se esperaba, lo que demuestra que de hecho aquí el problema es que hay una competencia entre derived::fun
y decorator::fun
.
Sin embargo, ¿por qué diablos se muestra esto con una deducción de tipo de retorno? Y más precisamente, ¿ por qué fue elegido este comportamiento por el comité?
Para hacer las cosas más fáciles, en Coliru:
¡Gracias!