59

Sé que la especificación de idioma prohíbe parcial especialización de plantilla de función.¿Por qué la plantilla de función no puede ser parcialmente especializada?

Me gustaría saber la razón por la que lo prohíbe? ¿No son útiles?

template<typename T, typename U> void f() {} //allowed! 
template<> void f<int, char>()   {} //allowed! 
template<typename T> void f<char, T>() {} //not allowed! 
template<typename T> void f<T, int>()  {} //not allowed! 
+0

Por 'plantilla void f (T t, U u) {}' también 'plantilla <> void f (int t, char u) {} 'está permitido. – dashesy

+2

Me parece interesante que las personas continúen proporcionando soluciones cuando la pregunta no es "¿cómo puedo lograr un objetivo similar" sino "cuál es la razón detrás de este comportamiento" ... Yo mismo no sé la razón de esta elección, pero asumo el comité debe haber tenido una razón para prohibir la especialización parcial de la plantilla de función. Hasta ahora, la explicación "más cercana" es el enlace publicado por Georgy, que solo señala los posibles "riesgos" de la especialización parcial de la plantilla de funciones cuando hay sobrecargas. Sin embargo, no creo que sea una razón para prohibir esta función, así que supongo que hay más en esto ... – bartgol

Respuesta

45

yo sepa lo que ha cambiado en C++ 0x.

Supongo que fue solo un descuido (teniendo en cuenta que siempre se puede obtener el efecto de especialización parcial con un código más detallado, al colocar la función como miembro static de una clase).

Puede buscar el DR relevante (Informe de defectos), si lo hay.

EDIT: comprobando esto, me parece que otros también lo han creído, pero nadie puede encontrar tal soporte en el borrador del estándar. This SO thread parece indicar que especialización parcial de plantillas de funciones no es compatible con C++ 0x.

EDIT 2: sólo un ejemplo de lo que quería decir con "la colocación de la función como miembro static de una clase":

#include <iostream> 
using namespace std; 

// template<typename T, typename U> void f() {} //allowed! 
// template<> void f<int, char>()   {} //allowed! 
// template<typename T> void f<char, T>() {} //not allowed! 
// template<typename T> void f<T, int>()  {} //not allowed! 

void say(char const s[]) { std::cout << s << std::endl; } 

namespace detail { 
    template< class T, class U > 
    struct F { 
     static void impl() { say("1. primary template"); } 
    }; 

    template<> 
    struct F<int, char> { 
     static void impl() { say("2. <int, char> explicit specialization"); } 
    }; 

    template< class T > 
    struct F< char, T > { 
     static void impl() { say("3. <char, T> partial specialization"); } 
    }; 

    template< class T > 
    struct F< T, int > { 
     static void impl() { say("4. <T, int> partial specialization"); } 
    }; 
} // namespace detail 

template< class T, class U > 
void f() { detail::F<T, U>::impl(); }  

int main() { 
    f<char const*, double>();  // 1 
    f<int, char>();     // 2 
    f<char, double>();    // 3 
    f<double, int>();    // 4 
} 
+0

¿tiene el estándar en n3225? Hice una búsqueda rápida pero no pude encontrarla:/ –

+0

@Matthieu M .: [n3225.pdf] (http://std.dkuug.dk/jtc1/sc2/wg2/docs/n3225.pdf) –

+1

Ah, perdón. .. una palabra faltaba. Tengo el documento, pero no pude encontrar el * párrafo * en particular.Aunque se le dio su edición, creo que es simplemente porque no está allí :) –

13

En general, no es recomendable para especializarse plantillas de función en absoluto, debido a problemas con la sobrecarga He aquí un buen artículo de la C/C++ Diario Usuarios: http://www.gotw.ca/publications/mill17.htm

Y contiene una respuesta sincera a su pregunta:

Por un lado, no se puede especializar en parte de ellos - más o menos sólo porque el lenguaje dice que no puedes.

+0

El artículo no trata sobre la especialización parcial además de que se menciona una vez. –

8

Bueno, realmente no se puede hacer una especialización parcial de función/método, pero se puede sobrecargar.

template <typename T, typename U> 
T fun(U pObj){...} 

// acts like partial specialization <T, int> AFAIK 
// (based on Modern C++ Design by Alexandrescu) 
template <typename T> 
T fun(int pObj){...} 

Es el camino, pero no sé si te satisface.

+1

Wow mi mente estaba llena de plantillas tales que realmente me olvidé de lo simple que podría ser :) – Johannes

6

Ya que se puede especializar parcialmente clases, puede utilizar un funtor:

#include <iostream> 

template < typename dtype , int k > struct fun 
{ 
int operator()() 
{ 
    return k ; 
} 
} ; 

template < typename dtype > struct fun < dtype , 0 > 
{ 
int operator()() 
{ 
    return 42 ; 
} 
} ; 

int main (int argc , char * argv[]) 
{ 
std::cout << fun<float,5>()() << std::endl ; 
std::cout << fun<float,0>()() << std::endl ; 
} 
+0

Puede utilizar una plantilla de función única para hacer las llamadas, deshacerse de la fea sintaxis '()()'. – tmr232

Cuestiones relacionadas