Question Pourquoi ce code C ++ lié à une surcharge / espace de noms / modèle n'est-il pas compilé?


Voici du code C ++:

namespace A {

int f(int x) { return 0; }
int f(long x) { return 1; }

template<class T> int g(T x) {
  return f(x);
}

}

namespace B {
struct C {};
}

namespace A {
int f(B::C x) { return 2; }
}

void h() {
  A::g(B::C());
}

Dans l'espace de noms A, le code déclare quelques surcharges d'une fonction f, et une fonction basée sur des modèles g qui appelle f. Ensuite, nous déclarons un nouveau type dans l'espace de noms B et une surcharge f pour le nouveau type dans l'espace de noms A. Compiler avec g ++ 4.2 donne

order.cpp: In function ‘int A::g(T) [with T = B::C]’:
order.cpp:21:   instantiated from here
order.cpp:7: error: no matching function for call to ‘f(B::C&)’
order.cpp:3: note: candidates are: int A::f(int)
order.cpp:4: note:                 int A::f(long int)

Le code fonctionne si je fais l'une des opérations suivantes:

  1. Supprimez les espaces de noms.
  2. Déplacez la surcharge de f pour B :: C dans l'espace de noms B (grâce à la recherche Koenig).
  3. Déplace la déclaration de B :: C et sa surcharge f au-dessus de la définition de g ().

Je suis particulièrement surpris (3), car j'avais l'impression que la résolution de la surcharge devrait être indépendante de l'ordre des déclarations. Ce comportement C ++ est-il attendu?


12
2017-12-02 22:59


origine


Réponses:


Clang donne le message d'erreur suivant, qui donne des indices sur le problème:

$ clang -fsyntax-only test.cc -Wall
test.cc:7:10: error: call to function 'f' that is neither visible in the
      template definition nor found by argument-dependent lookup
  return f(x);
         ^
test.cc:21:3: note: in instantiation of function template specialization
      'A::g<B::C>' requested here
  A::g(B::C());
  ^
test.cc:17:5: note: 'f' should be declared prior to the call site or in
      namespace 'B'
int f(B::C x) { return 2; }
    ^
1 error generated.

Plus précisément, vous rencontrez un détail de recherche en deux phases de noms dépendants dans les définitions de modèle. En C ++ 98, [temp.dep.candidate] dit:

Pour un appel de fonction qui dépend d'un paramètre de modèle, si le nom de la fonction est un identificateur non qualifié mais pas un identifiant de modèle, les fonctions candidates sont trouvées en utilisant les règles de recherche habituelles (3.4.1, 3.4.2), sauf que:

  • Pour la partie de la recherche utilisant la recherche de nom non qualifiée (3.4.1), seules les déclarations de fonction avec un lien externe provenant du contexte de définition de modèle sont trouvées.
  • Pour la partie de la recherche utilisant des espaces de noms associés (3.4.2), seules les déclarations de fonction avec un lien externe trouvées dans le contexte de définition du modèle ou dans le contexte d'instanciation du modèle sont trouvées.

Depuis A::f(B::C x) n'est pas trouvé en utilisant les espaces de noms associés (c'est-à-dire la recherche dépendante des arguments), il doit être visible sur le site de définition du modèle, pas seulement au moment de l'instanciation.


6
2017-12-15 07:44



Par exemple

int f(int x) { return 0; }
int f(long x) { return 1; }

les fonctions ne sont pas des fonctions de modèle (c’est-à-dire qu’elles n’ont pas de template <class T> avant eux. T est un paramètre de modèle.) Par conséquent, ils peuvent être compilés à la volée lorsque le code modélisé est atteint.


0
2017-12-02 23:32