Arguments de modèle par défaut pour les modèles de fonction

Pourquoi les arguments de modèle par défaut sont-ils autorisés uniquement sur les modèles de classe? Pourquoi ne pouvons-nous pas définir un type par défaut dans un modèle de fonction membre? Par exemple:

struct mycclass { template void mymember(T* vec) { // ... } }; 

Au lieu de cela, C ++ force les arguments de modèle par défaut uniquement sur un modèle de classe.

Il est logique de donner des arguments de modèle par défaut. Par exemple, vous pouvez créer une fonction de sorting:

 template::value_type> > void sort(Iterator beg, Iterator end, Comp c = Comp()) { ... } 

C ++ 0x les présente à C ++. Voir ce rapport de défaut par Bjarne Stroustrup: Arguments de modèle par défaut pour les modèles de fonction et ce qu’il dit

L’interdiction des arguments de modèle par défaut pour les modèles de fonction est un résidu mal interprété du temps où les fonctions autonomes étaient traitées comme des citoyens de deuxième classe et exigeaient que tous les arguments de modèle soient déduits des arguments de fonction plutôt que spécifiés.

La ressortingction compromet sérieusement le style de programmation en rendant inutilement différentes fonctions autonomes des fonctions membres, ce qui rend plus difficile l’écriture de code de style STL.

Pour citer les modèles C ++: le guide complet (page 207):

Lorsque des modèles ont été initialement ajoutés au langage C ++, les arguments de modèles de fonctions explicites n’étaient pas une construction valide. Les arguments du modèle de fonction devaient toujours être déductibles de l’expression d’appel. Par conséquent, il ne semblait pas y avoir de raison impérieuse d’autoriser les arguments de modèle de fonction par défaut, car la valeur déduite remplacerait toujours la valeur par défaut.

Jusqu’à présent, tous les exemples de parameters de modèle par défaut proposés pour les modèles de fonction peuvent être réalisés avec des surcharges.

AraK:

 struct S { template  R get_me_R() { return R(); } }; 

pourrait être:

 struct S { template  R get_me_R() { return R(); } int get_me_R() { return int(); } }; 

Le mien:

 template  int &increment(int &i) { i += N; return i; } 

pourrait être:

 template  int &increment(int &i) { i += N; return i; } int &increment(int &i) { return increment<1>(i); } 

litb:

 template > void sort(Iterator beg, Iterator end, Comp c = Comp()) 

pourrait être:

 template void sort(Iterator beg, Iterator end, std::less c = std::less()) template void sort(Iterator beg, Iterator end, Comp c = Comp()) 

Stroustrup:

 template  void f(T t = 0, U u = 0); 

Pourrait être:

 template  void f(S s = 0, T t = 0); template  void f(S s = 0, double t = 0); 

Ce que j’ai prouvé avec le code suivant:

 #include  #include  #include  #include  template  T prettify(T t) { return t; } std::ssortingng prettify(char c) { std::ssortingngstream ss; if (isprint((unsigned char)c)) { ss << "'" << c << "'"; } else { ss << (int)c; } return ss.str(); } template  void g(S s, T t){ std::cout << "f<" << typeid(S).name() << "," << typeid(T).name() << ">(" << s << "," << prettify(t) << ")\n"; } template  void f(S s = 0, T t = 0){ g(s,t); } template  void f(S s = 0, double t = 0) { g(s, t); } int main() { f(1, 'c'); // f(1,'c') f(1); // f(1,0) // f(); // error: T cannot be deduced f(); // f(0,0) f(); // f(0,0) } 

La sortie imprimée correspond aux commentaires de chaque appel à f, et l’appel commenté ne peut pas être compilé comme prévu.

Je pense donc que les parameters de modèle par défaut “ne sont pas nécessaires”, mais probablement uniquement dans le même sens que les arguments de fonction par défaut “ne sont pas nécessaires”. Comme l’indique le rapport de défaut de Stroustrup, l’ajout de parameters non déduits était trop tard pour que quiconque puisse se rendre compte et / ou comprenne que cela rendait les parameters par défaut utiles. Ainsi, la situation actuelle est basée sur une version des modèles de fonction qui n’a jamais été standard.

Sous Windows, avec toutes les versions de Visual Studio, vous pouvez convertir cette erreur ( C4519 ) en un avertissement ou le désactiver comme suit :

 #ifdef _MSC_VER #pragma warning(1 : 4519) // convert error C4519 to warning // #pragma warning(disable : 4519) // disable error C4519 #endif 

Voir plus de détails ici .

Ce que j’utilise est la prochaine astuce:

Disons que vous voulez avoir une fonction comme celle-ci:

 template  > void doStuff(ARR_E array) { E one(1); array.add( one ); } 

Vous ne serez pas autorisé, mais je le ferai ensuite:

 template  struct MyArray_t { void add(T i) { // ... } }; template  > class worker { public: /*static - as you wish */ ARR_E* parr_; void doStuff(); /* do not make this one static also, MSVC complains */ }; template  void worker::doStuff() { E one(1); parr_->add( one ); } 

Ainsi, vous pouvez l’utiliser comme ceci:

 MyArray_t my_array; worker w; w.parr_ = &arr; w.doStuff(); 

Comme on ne voit pas besoin de définir explicitement le deuxième paramètre. Peut-être que ce sera utile pour quelqu’un.