Question

Veuillez considérer ce code:

template<typename T>
char (&f(T[1]))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

Je m'attendais à ce que SFINAE et la deuxième surcharge soient choisis, car la substitution de T par T [1] donne

 void [1]()

Ce qui est un type invalide, bien sûr. Le réglage des types de paramètres (tableau- pointeur) est effectué après substitution des paramètres de modèle aux paramètres de fonction et recherche de types de résultat valables, tels que 14.8.2 [temp.deduct] décrit.

Mais Comeau et GCC ne parviennent pas à compiler ce qui précède. Les deux avec des diagnostics différents.

Comeau dit:

  

"ComeauTest.c", ligne 2: erreur: le tableau de fonctions n'est pas autorisé char (& amp; f (T [1])) [1];

GCC dit (version 4.3.3 ):

  

erreur: ISO C ++ interdit les tableaux de taille nulle c

Signification, GCC ne manque pas de substituer, mais il choisit la première surcharge de f , en renvoyant un sizeof de 1, au lieu de ne pas le substituer immédiatement comme Comeau.

Quel compilateur a raison et mon code est-il valide? Veuillez vous référer ou citer la section Standard appropriée dans votre réponse. Merci!

Mise à jour : la norme elle-même contient un exemple dans la liste 14.8.2 / 2 . Je ne sais pas pourquoi je l’ai oublié en premier:

template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array

Bien que l'exemple ne soit qu'informatif, il montre l'intention de tous ces paragraphes mystérieux et semble indiquer que le code ci-dessus devrait fonctionner et rejeter la première surcharge.

Était-ce utile?

La solution

Une petite note, bien que très rare, j’ai trouvé quelques occasions où je croient que le compilateur Comeau a tort - bien que ces les occasions sont si rares que sa vaut toujours le double et le triple vérifier vos hypothèses!

Je peux avoir une raison pour le comportement de g ++. Je ne suis pas sûr que ce soit spécifié exactement quand les types de paramètres sont ajustés:

Considérez ce qui suit:

template<typename T>
struct A
{
  void bar (T[10]);
};

template<typename T>
void A<T>::bar (T*)
{
}

La définition de "bar" est légale, en tant que "T [10]" se désintègre en "T *". je fais ne rien voir dans la norme qui empêche le compilateur de effectuer les ajustements de 8.3.5 par rapport au modèle de déclaration, et cela améliore également les performances en matière de correspondance de surcharge.

En appliquant ceci à votre exemple, g ++ pourrait le traiter comme suit:

template<typename T>
char (&f( T* ))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

Dans ce qui précède, le paramètre substitué est un pointeur juridique vers fonction, plutôt que d'un tableau de fonctions.

Donc, la question pour moi est - est-ce qu'il y a quelque chose qui interdit les réglages pour les paramètres de fonction (8.3.5) deux fois?

Personnellement, je pense qu'il est logique d'autoriser les ajustements deux fois, sinon cela complique l'appariement du modèle de fonction surcharges

En conclusion, je pense que c’est valable pour g ++ de sélectionner la première surcharge basé sur la façon dont il traite les paramètres de tableau en décomposition, et Comeau a tort ne pas avoir d'échec de déduction pour le tableau de fonctions.

Bien sûr, cela signifie maintenant que (si Comeau était corrigé), chaque compilateur choisirait une surcharge différente et serait toujours des normes conforme! : (

EDIT:

Juste pour illustrer mon propos, considérons le code suivant:

template <typename T> void foo ( T * );
template <typename T> void foo ( T * const );
template <typename T> void foo ( T [] );
template <typename T> void foo ( T [10] );
template <typename T> void foo ( T [100] );

void bar () 
{
  foo < void() > ( 0 );
}

Ici, foo a été déclaré et redéclaré plusieurs fois. Quelle déclaration, et donc quel type de paramètre, le compilateur doit-il appliquer les règles énumérées à la section 14.8.2?

Mon point est que la norme ne dit rien à propos de ce qui précède. J'irais aussi jusqu'à dire que toute formulation à ce sujet devrait laisser le terme "indéfini". ou " implémentation définie " comportement.

Autres conseils

Étonnamment - cela fonctionne dans VS2008. Je ne pense pas que ce soit nécessairement une preuve de comportement correct ou non

.

Visual Studio interprète

char (&f(T[1]))[1];

en tant que fonction qui prend un tableau de taille 1 sur T et renvoie une référence à un tableau de caractères de taille 1.

Je vais essayer de décrire le processus de déduction des arguments de modèle tel que je le comprends à la lecture de la norme.

  1. Les arguments de modèles explicites sont vérifiés comme décrit dans 14.8.2 / 2.
  2. La signature de fonction résultante est ajustée conformément à 8.3.5 (c’est-à-dire que la désintégration entre les points est effectuée).
  3. Les arguments de modèle implicites sont déduits conformément à 14.8.2.1 (cette opération est effectuée sur une signature partiellement substituée à partir de l'étape 2).

La déduction pour la première surcharge échoue à l'étape 1; la résolution de la surcharge renvoie donc la seconde surcharge. Je ne crois pas que le programme soit mal formé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top