Question

Considérez le code suivant:

#include <stdio.h>

namespace Foo {
  template <typename T>
  void foo(T *, int) { puts("T"); }

  template <typename T>
  struct foo_fun {
    static void fun() { foo((T *)0, 0); };
  };
}

namespace Foo {
  void foo(int *, int) { puts("int"); }
}

using namespace Foo;

int main() {
  foo_fun<int> fun;
  fun.fun();
}

Quel est le résultat attendu? " T " ou int?

Un compilateur (gcc 4.0.1 issu du Xcode 3.1.2 d’Apple) générant la sortie "int", deux autres compilateurs (gcc 4.1.2 et 4.1.3) générant la sortie "T".

Si je déplace la déclaration / définition de foo (int *, int) avant la version de foo (T *, int), toutes les sorties "quot". Dans ce cas, l’ordre de surcharge / spécialisation est-il défini par la norme actuelle?

Était-ce utile?

La solution

Le second void foo (... est une surcharge (et non une spécialisation) qui n'est pas visible à la définition de foo_fun :: fun , donc il a gagné ' t être trouvé dans le contexte de la définition du modèle, car T * est un type dépendant, résolution de toto dans l’expression toto ((T *) 0, 0) sera retardé jusqu'à l'heure d'instanciation du modèle et le contexte de l'instanciation sera également pris en compte.Toutefois, 14.6.4.2 de la norme indique que si le nom de la fonction est un identificateur non qualifié mais pas un template-id , alors pour la recherche non-ADL, seules les fonctions visibles au moment de la définition du modèle sont considérées. Il n'y a pas d'argument de fonction dans l'espace de nom Foo , donc aucune recherche dépendant d'argument ne se produit, la version du modèle de foo est donc appelée et non la surcharge non-modèle.

Merci beaucoup à litb pour les corrections apportées à cette réponse.

Si vous avez défini une spécialisation comme ci-dessous, les spécialisations étant choisies au moment de l'instanciation du modèle, vous pouvez appeler cette spécialisation tant que la spécialisation correspondante est visible au point où le modèle de fonction est instancié pour . int .

namespace Foo {
    template<>
    void foo<int>(int *, int) { puts("int"); }
}

Chapitre 14 de la norme actuelle, mais ce n'est pas très lisible:)

Éditer: Si je devais choisir la partie la plus pertinente de la norme, elle serait probablement 14.6 [temp.res] para 9. (légèrement abrégé) Si un nom ne dépend pas d'un template-paramètre , une déclaration pour ce nom doit figurer dans la portée à l'endroit où le nom apparaît dans la définition du modèle; le nom est lié à la déclaration trouvée à cet endroit et cette liaison n'est pas affectée par les déclarations visibles au moment de l'instanciation.

Modifier, modifier: Mais vous devez également prendre en compte 14.6.4.2 [temp.dep.candidate]. Il est très difficile et dangereux de faire référence à la norme en raison de toutes les interdépendances. Cette réponse est un exemple typique.

Autres conseils

En règle générale, sur deux versions d'un compilateur, la dernière est plus susceptible d'être plus standard.

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