11

Tengo una función de plantilla variadic que se llama a sí misma para determinar el número más grande en una lista (constituido por los argumentos de plantilla). Estoy tratando de hacer una especialización para cuando el paquete de parámetros está vacío, así que puedo devolver el número al principio de la lista, pero no sé cómo hacerlo. Estoy familiarizarse con las plantillas variadic y especialización de plantilla, pero esto es lo que tengo hasta ahora:Especialización de plantilla para un paquete de parámetros vacío

#include <string> 
#include <iostream> 

using namespace std; 

template <int N, int... N2> 
int tmax() { 
    return N > tmax<N2...>() ? N : tmax<N2...>(); 
} 

template <int N> 
int tmax() { 
    return N; 
} 

int main() { 
    cout << tmax<32, 43, 54, 12, 23, 34>(); 
} 

Sin embargo, esto produce el siguiente error:

test.cpp: In function ‘int tmax() [with int N = 34, int ...N2 = {}]’: 
test.cpp:9:45: instantiated from ‘int tmax() [with int N = 23, int ...N2 = {34}]’ 
test.cpp:9:45: instantiated from ‘int tmax() [with int N = 12, int ...N2 = {23, 34}]’ 
test.cpp:9:45: instantiated from ‘int tmax() [with int N = 54, int ...N2 = {12, 23, 34}]’ 
test.cpp:9:45: instantiated from ‘int tmax() [with int N = 43, int ...N2 = {54, 12, 23, 34}]’ 
test.cpp:9:45: instantiated from ‘int tmax() [with int N = 32, int ...N2 = {43, 54, 12, 23, 34}]’ 
test.cpp:18:39: instantiated from here 
test.cpp:9:45: error: no matching function for call to ‘tmax()’ 
test.cpp:9:45: error: no matching function for call to ‘tmax()’ 

También he probado esto, sólo para ver si iba a funcionar (si bien introduce el número 0 a la lista de forma aleatoria por lo que no puede nunca volver un número inferior a 0):

template <int N, int... N2> 
int tmax() { 
    return N > tmax<N2...>() ? N : tmax<N2...>(); 
} 

template <> 
int tmax<>() { 
    return 0; 
} 

sin embargo, Además a los errores mencionados anteriormente, me sale este error:

error: template-id ‘tmax<>’ for ‘int tmax()’ does not match any template declaration 

Entonces, ¿qué debo hacer para conseguir este trabajo?

Estoy usando g ++ 4.5.2 con la bandera -std=c++0x.

Respuesta

22

Veo dos errores al usar clang.

  1. Ponga la sobrecarga de tomar una sola int primero.

  2. Haga que las cosas no sean ambiguas para las listas de longitud 1. Recuerde que las listas variadas pueden tener un tamaño cero y, cuando lo hacen, me parece que tiene una ambigüedad.

Esto compila y se ejecuta correctamente para mí:

#include <iostream> 

using namespace std; 

template <int N> 
int tmax() { 
    return N; 
} 

template <int N, int N1, int... N2> 
int tmax() { 
    return N > tmax<N1, N2...>() ? N : tmax<N1, N2...>(); 
} 

int main() { 
    cout << tmax<32, 43, 54, 12, 23, 34>(); 
} 
+1

Optimal, gracias. –

+1

La necesidad de "dividir" explícitamente el paquete de parámetros de una manera cabeza/cola ya me ha mordido un montón de veces, espero que nos acostumbremos ... sin embargo, no creo que poner el caso base primero sea obligatorio , como es, generalmente los pongo inmediatamente después. –

0

Puesto que no puede especializarse parcialmente funciones, es necesario envolver su funcionalidad:

template<int Head, int... Tail> 
struct Tmax{ 
    static int do(){ 
    return Head > Tmax<Tail...>::do() ? Head : Tmax<Tail...>::do(); 
    } 
}; 

template<int N> 
struct Tmax<N>{ 
    static int do(){ 
    return N; 
    } 
}; 

template<int... Numbers> 
int tmax(){ 
    return Tmax<Numbers...>::do(); 
} 
+0

no está seguro de si es legal, pero g ++ - 4.5.1 parece que no le gusta su respuesta: http: // Ideone .com/VXqHv No tengo a mano mi copia del estándar, así que no estoy seguro de si es un problema real o un compilador antiguo. – Lambdageek

5

Personalmente, prefiero usar miembros de la clase estática sobre las funciones para este tipo de cosas:

template <int... N> struct max; 
template <int N, int... M> struct max<N, M...> { 
    static const int value = max<N, max<M...>::value>::value; 
};  
template <int N, int M> struct max<N, M> { 
    static const int value = N > M ? N : M; 
}; 

int main() 
{ 
    return max<1,2,3>::value; 
} 

actualización: el uso de la sugerencia de Ildjarn, aquí está la versión menos detallado:

#include <type_traits> 
template <int... N> struct max; 
template <int N, int... M> struct max<N, M...> 
    : std::integral_constant<int, max<N, max<M...>::value>::value> { }; 
template <int N, int M> struct max<N, M> 
    : std::integral_constant<int, (N > M ? N : M)> { }; 
+0

+1, aunque personalmente derivaría de 'std :: integral_constant' en lugar de declarar' value' manualmente. – ildjarn

+0

@ildjarn: ¡Gracias, actualizado! Siempre es bueno para mantener las cosas concisas :-) –

+0

¿qué tal: 'plantilla struct max \t: integral_constant {}; plantilla struct max \t: integral_constant max :: value? a: max :: value)> {}; ' – sluki

Cuestiones relacionadas