ventajas sirve que para lenguaje historia fuente ejemplos dev desventajas codigo caracteristicas c++ templates c++17 template-deduction

lenguaje - para que sirve c++



¿Cómo puede un compilador deducir esta plantilla de clase con referencia de reenvío? (1)

La deducción de argumentos de la plantilla de clase ocurre en dos etapas.

  1. Deducir los argumentos de la plantilla de clase.
  2. Luego, hacer la construcción real con el tipo de clase de concreto.

El paso 1 solo te ayuda a descubrir los argumentos de la plantilla de clase. No hace nada con respecto al constructor real (o la especialización de plantilla de clase) que se puede usar en el paso 2.

La existencia de los constructores podría impulsar la deducción, pero si un constructor determinado se usa para deducir eso no dice si se usó o no para construir.

Entonces, cuando solo tienes:

template<typename T> struct MyAbs { template<typename U> MyAbs(U&& u); };

La deducción de argumentos de la plantilla de clase falla: no tiene una guía de deducción en su constructor, T es un contexto no deducido. El compilador simplemente no puede averiguar qué T quieres en MyAbs(4.7) o MyAbs(d) .

Cuando agregaste este:

template<typename T> struct MyAbs { template<typename U> MyAbs(U&& u); MyAbs(T const&); };

Ahora puede! En ambos casos, deduce T como double . Y una vez que lo hace, seguimos adelante y realizamos la resolución de sobrecarga como si hubiéramos escrito MyAbs<double> para empezar.

Y aquí, MyAbs<double>(4.7) pasa a preferir el constructor de referencia de reenvío (referencia menos calificada en MyAbs<double>(d) ), mientras que MyAbs<double>(d) prefiere al otro (no se prefiere la plantilla a la plantilla). Y eso está bien y se espera, solo porque usamos un constructor para la deducción no significa que tengamos que usar específicamente ese constructor para la construcción.

Estoy buscando deducción de plantilla de clase disponible desde C ++ 17. Aquí está el código que me gustaría preguntar sobre:

#include <iostream> #include <cmath> using std::endl; using std::cout; template<typename T> struct MyAbs { template<typename U> MyAbs(U&& u) : t(std::forward<T>(u)) { cout << "template" << endl;} #ifdef ON MyAbs(const T& t) : t(t) {} #endif T operator()() const { return std::abs(t); } T t; }; /* // may need the following template<typename U> MyAbs(U&&) -> MyAbs<typename std::remove_reference<U>::type>; */ int main() { const double d = 3.14; cout << MyAbs(4.7)() << endl; cout << MyAbs(d)() << endl; return 0; }

Cuando MyAbs(const T&) no se compila condicionalmente (es decir, no -DON ), tanto clang ++ como g ++ no pueden deducir el parámetro de la plantilla, T Dado -DON=1 , ambos compiladores construyen el sencillo ejemplo anterior.

En primer lugar, también supuse que la deducción debería fallar; El compilador podría deducir U pero no T Los errores de compilación que obtuve fueron los que esperaba. Por favor, avísame si estoy equivocado.

Si tuve razón al respecto, entonces, no puedo entender por qué la deducción con U&& exitosa cuando se MyAbs(const T&) . Lo que esperaba era deducir con U&& falla, y SFINAE me permite invocar MyAbs(const T&) en ambos casos: 4.7 y d. Sin embargo, lo que sucedió es diferente. Este programa parece invocar la versión de la plantilla para 4.7 y la versión sin plantilla para d .

$ g++ -Wall -std=c++17 ~/a.cc -DON=1 $ ./a.out template 4.7 3.14

Parece que la versión de la plantilla se ha vuelto repentinamente viable. ¿Se espera esto? Si es así, ¿cuál es la razón?