Pourquoi le modèle de fonction ne peut pas être partiellement spécialisé?

87

Je sais que la spécification du langage interdit la spécialisation partielle du modèle de fonction.

J'aimerais savoir pourquoi il l'interdit? Ne sont-ils pas utiles?

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!
Nawaz
la source
Car template<typename T, typename U> void f(T t, U u) {}aussi template<> void f(int t, char u) {}est autorisé.
dashesy le
10
Je trouve intéressant que les gens continuent à fournir des solutions de contournement lorsque la question n'est pas "comment puis-je atteindre un objectif similaire" mais "quelle est la raison d'être de ce comportement" ... Je ne connais pas moi-même la raison de ce choix, mais je suppose que Le comité doit avoir une raison d'interdire la spécialisation partielle des modèles de fonctions. Jusqu'à présent, l'explication "la plus proche" est le lien posté par Georgy, qui ne souligne que les "risques" potentiels de la spécialisation partielle du modèle de fonction en cas de surcharge. Cependant, je ne pense pas que ce soit une raison pour interdire cette fonctionnalité, donc je suppose qu'il y a plus à cela ..
bartgol

Réponses:

59

AFAIK qui a changé dans C ++ 0x.

Je suppose que c'était juste un oubli (étant donné que vous pouvez toujours obtenir l'effet de spécialisation partielle avec un code plus détaillé, en plaçant la fonction en tant que staticmembre d'une classe).

Vous pouvez rechercher le DR (rapport d'anomalie) pertinent, s'il y en a un.

EDIT : en vérifiant cela, je trouve que d'autres ont également cru cela, mais personne n'est en mesure de trouver un tel soutien dans le projet de norme. Ce thread SO semble indiquer que la spécialisation partielle des modèles de fonctions n'est pas prise en charge dans C ++ 0x .

EDIT 2 : juste un exemple de ce que je voulais dire par "placer la fonction comme staticmembre d'une classe":

#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
}
Bravo et hth. - Alf
la source
avez-vous la norme en n3225? J'ai fait une recherche rapide mais je ne l'ai pas trouvée: /
Matthieu M.
1
ah désolé ... un mot manquait. J'ai le document, mais je n'ai pas pu trouver le paragraphe en question . Bien que compte tenu de votre modification, je suppose que c'est simplement parce que ce n'est pas là :)
Matthieu M.
3
Cela n'est pas modifié dans C ++ 0x. Je doute également de son utilité. Vous pouvez toujours surcharger le modèle et utiliser une commande partielle .
Johannes Schaub - litb
1
Mise à jour tardive: n'a pas changé même en C ++ 17 huit ans plus tard, et ne semble pas non plus entrer en C ++ 20. Je ne vois aucune raison pour, cependant ...
Aconcagua
C'est de loin la mise en œuvre la plus complète du concept, je crois
Victor
18

Eh bien, vous ne pouvez vraiment pas faire de spécialisation partielle de fonction / méthode, mais vous pouvez effectuer une surcharge.

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){...} 

C'est le chemin mais je ne sais pas si cela vous satisfait.

Michal W
la source
1
Wow, mon esprit était rempli de modèles tels que j'ai vraiment oublié à quel point les choses pouvaient être simples :)
Johannes
1
Malheureusement, ce n'est pas le cas lorsque vous voulez passer des arguments variadiques après avoir partiellement spécialisé la fonction. :(
Gwangmu Lee
Je ne suis pas sûr de ce que signifiait le passage de modèles variadiques, alors j'aimerais savoir en quoi il est différent d'une spécialisation partielle. Pourriez-vous s'il vous plaît fournir plus de détails?
beginpluses
Et si vous ne voulez que deux fonctions pour tous les types intégraux et flottants?
Dmitriy Dokshin le
14

En général, il n'est pas du tout recommandé de spécialiser les modèles de fonctions, en raison de problèmes de surcharge. Voici un bon article du Journal des utilisateurs C / C ++: http://www.gotw.ca/publications/mill17.htm

Et il contient une réponse honnête à votre question:

D'une part, vous ne pouvez pas les spécialiser partiellement - à peu près simplement parce que la langue dit que vous ne pouvez pas.

Georgy Pashkov
la source
3
L'article ne concerne pas la spécialisation partielle en plus d'être mentionné une fois.
Euri Pinhollow
11

Puisque vous pouvez partiellement spécialiser les classes, vous pouvez utiliser un foncteur:

#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 ;
}
Kay F. Jahnke
la source
1
Vous pouvez ensuite utiliser un seul modèle de fonction pour effectuer les appels, en vous débarrassant de la ()()syntaxe laide .
tmr232