2012-08-22 6 views
22

Supongamos que tengo una función de plantilla:C++ 11: Plantilla de especialización de funciones de los tipos enteros

template<typename T> 
void f(T t) 
{ 
    ... 
} 

y yo quiero escribir una especialización para todos los tipos enteros primitivos. ¿Cuál es la mejor manera de hacer esto?

Lo que quiero decir es:

template<typename I where is_integral<I>::value is true> 
void f(I i) 
{ 
    ... 
} 

y el compilador selecciona la segunda versión de los tipos enteros, y la primera versión para todo lo demás?

+0

¿Hay especialización de plantillas para funciones en C++ 11? Creo que en C++ 03 solo estaba sobrecargando. –

+0

He estado buscando algo similar, pero fallé. todo lo que podía hacer era simplemente definir una plantilla normal, y en el interior compruebo si el parámetro dado es del tipo integral –

+3

@AlexanderChertov, está en C++ 03, pero [es complicado] (http://www.gotw.ca) /publications/mill17.htm). Lo mismo se aplica a C++ 11. – juanchopanza

Respuesta

36

Uso SFINAE

// For all types except integral types: 
template<typename T> 
typename std::enable_if<!std::is_integral<T>::value>::type f(T t) 
{ 
    // ... 
} 

// For integral types only: 
template<typename T> 
typename std::enable_if<std::is_integral<T>::value>::type f(T t) 
{ 
    // ... 
} 

Tenga en cuenta que tendrá que incluir la plena std::enable_if valor de retorno incluso para la declaración.

+1

Ha cambiado el valor de retorno de la función de vacío a algo más. ¿Qué pasa si la función original devolvió un tipo? Por ejemplo, una clase X? 'plantilla X f (T t)'? ¿Cómo se vería entonces? –

+0

@ AndrewTomazos-Fathomling, 'std :: ebable_if :: type' es nulo, si se le da solo 1 parámetro de plantilla; o el segundo parámetro de plantilla. – Lol4t0

+1

@ AndrewTomazos-Fathomling El segundo argumento de la plantilla de 'std :: enable_if' está predeterminado en' void'. Ese es tu tipo de devolución. Lo dejé por defecto, pero puedes cambiarlo al tipo de devolución que quieras. Incluso puede hacer que los tipos integrales devuelvan un tipo diferente que los tipos no integrales. – David

11

usando C++ 11, std :: enable_if (http://en.cppreference.com/w/cpp/types/enable_if) se puede utilizar para hacer eso:

template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type> 
void f(T t) {...} 
+0

¿Es código válido? – Andrey

+1

Casi, pero lo hizo mal. – David

+0

editado :) ¡la sintaxis es bastante complicada! – arnoo

7

Usted puede utilizar una plantilla auxiliar que puede especializarse como esto:

#include <string> 
#include <iostream> 
#include <type_traits> 

template <typename T, bool = std::is_integral<T>::value> 
struct Foo { 
     static void bar(const T& t) { std::cout << "generic: " << t << "\n"; } 
}; 
template <typename T> 
struct Foo<T, true> { 
     static void bar(const T& t) { std::cout << "integral: " << t << "\n"; } 
}; 

template <typename T> 
static void bar(const T& t) { 
     return Foo<T>::bar(t); 
} 

int main() { 
     std::string s = "string"; 
     bar(s); 
     int i = 42; 
     bar(i); 
     return 0; 
} 

de salida:

generic: string 
integral: 42 
+1

+1 para el delegado de plantilla de clase, ya que esto permite no solo explícito sino también parcial especialización. Esto también está en línea con el artículo 66 de las Normas de Codificación de Sutter & Alexandrescu: "no se especializan las plantillas de funciones". – TemplateRex

+0

@rhalbersma Me gusta esta respuesta, pero no creo que su razonamiento sea correcto. . Simplemente no es una opción práctica para usar la especialización de plantilla de función para este problema. – David

+0

La pregunta en sí solicitó "especialización". – mitchnull

19

me gustaría utilizar la resolución de sobrecarga. Eso le evita tener que usar el truco bruto de SFINAE. Desafortunadamente, hay muchas áreas donde no puedes evitarlo, pero afortunadamente no es uno de esos.

template<typename T> 
void f(T t) 
{ 
    f(t, std::is_integral<T>()); 
} 

template<typename T> 
void f(T t, std::true_type) 
{ 
    // ... 
} 

template<typename T> 
void f(T t, std::false_type) 
{ 
    // ... 
} 
Cuestiones relacionadas