tipo de retorno final usando decltype con una función de plantilla variadica

Quiero escribir un sumdor simple (para risitas) que sum todos los argumentos y devuelve una sum con el tipo apropiado. Actualmente, tengo esto:

#include  using namespace std; template  T sum(const T& in) { return in; } template  auto sum(const T& t, const P&... p) -> decltype(t + sum(p...)) { return t + sum(p...); } int main() { cout << sum(5, 10.0, 22.2) << endl; } 

En GCC 4.5.1, esto parece funcionar bien para 2 argumentos, por ejemplo, sum (2, 5.5) regresa con 7.5. Sin embargo, con más argumentos que esto, recibo errores de que sum () simplemente no está definido aún. Si declaro sum () como este sin embargo:

 template  T sum(const T& t, const P&... p); 

Entonces funciona para cualquier cantidad de argumentos, pero sum (2, 5.5) devolvería el entero 7, que no es lo que yo esperaría. Con más de dos argumentos supongo que decltype () tendría que hacer algún tipo de recursión para poder deducir el tipo de t + sum (p …). ¿Es esto legal C ++ 0x? o ¿decltype () solo funciona con declaraciones no variadicas? Si ese es el caso, ¿cómo escribirías esa función?

Creo que el problema es que la plantilla de función variadic solo se considera declarada después de haber especificado su tipo de devolución, de modo que esa sum en decltype no puede referirse nunca a la plantilla de función variadic. Pero no estoy seguro de si esto es un error de GCC o C ++ 0x simplemente no lo permite. Supongo que C ++ 0x no permite una llamada “recursiva” en la parte ->decltype(expr) .

Como solución, podemos evitar esta llamada “recursiva” en ->decltype(expr) con una clase de rasgos personalizada:

 #include  #include  using namespace std; template typename std::add_rvalue_reference::type val(); template struct id{typedef T type;}; template struct sum_type; template struct sum_type : id {}; template struct sum_type : sum_type< decltype( val() + val() ), P... > {}; 

De esta forma, podemos reemplazar el tipo de decltype en su progtwig con typename sum_type::type y comstackrá.

Editar: Dado que esto realmente devuelve decltype((a+b)+c) lugar de decltype(a+(b+c)) que estaría más cerca de cómo se usa la sum, podría reemplazar la última especialización con esto:

 template struct sum_type : id() + val::type>() )>{}; 

Aparentemente no puedes usar decltype de forma recursiva (al menos por el momento, tal vez lo arreglen)

Puede usar una estructura de plantilla para determinar el tipo de la sum

Se ve feo pero funciona

 #include  using namespace std; template struct TypeOfSum; template struct TypeOfSum { typedef T type; }; template struct TypeOfSum { typedef decltype(T() + typename TypeOfSum

::type()) type; }; template T sum(const T& in) { return in; } template typename TypeOfSum::type sum(const T& t, const P&... p) { return t + sum(p...); } int main() { cout < < sum(5, 10.0, 22.2) << endl; }

La solución de C ++ 14:

 template  auto sum(const T& t, const P&... p){ return t + sum(p...); } 

El tipo de devolución se deduce automáticamente.

Véalo en el comstackdor en línea

Otra respuesta a la última pregunta con menos tipeo al usar std::common_type C ++ 11: Simplemente use

 std::common_type::type 

como tipo de devolución de su sum variable.

En cuanto a std::common_type , aquí hay un extracto de http://en.cppreference.com/w/cpp/types/common_type :

Para tipos aritméticos, el tipo común también se puede ver como el tipo de expresión aritmética (posiblemente modo mixto) como T0 () + T1 () + … + Tn ().

Pero obviamente esto funciona solo para expresiones aritméticas y no cura el problema general.

Proporciono esta mejora a la respuesta aceptada. Solo dos estructuras

 #include  template  struct sum_type { using type = decltype(std::declval

() + std::declval::type>()); }; template struct sum_type

{ using type = P; };

Ahora solo declara tus funciones como

 template  auto sum(const T& in) -> T { return in; } template  auto sum(const P& t, const Ps&... ps) -> typename sum_type

::type { return t + sum(ps...); }

Con esto, tu código de prueba ahora funciona

 std::cout < < sum(5, 10.0, 22.2, 33, 21.3, 55) << std::endl; 

146.5