Question

Quelle partie de la personne à charge C ++ spécification argument restreint recherche de trouver des modèles de fonction dans l'ensemble des espaces de noms associés? En d'autres termes, pourquoi le dernier appel en main ci-dessous ne parviennent pas à compiler?

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
    void non_template(foo const&) {}
}

int main() {
    ns::foo f;
    non_template(f); // This is fine.
    frob<0>(f); // This is not.
}
Était-ce utile?

La solution

Cette partie explique:

C ++ standard 03 14.8.1.6 :

[Note: Pour les noms simples de fonction, l'argument recherche dépendante (3.4.2) applique même lorsque le nom de la fonction ne soit pas visible dans le cadre de l'appel. En effet, l'appel a encore la forme syntaxique d'un appel de fonction (3.4.1). Mais quand un modèle de fonction avec des arguments de modèle explicite est utilisé, l'appel n'a pas la forme syntaxique correcte à moins d'un modèle de fonction avec ce nom visible au point de l'appel. Si un tel nom est visible, l'appel n'a pas syntaxiquement bien formée et recherche dépendante-argument ne vaut pas. Si un nom tel est visible, la recherche dépend des arguments et applique des modèles de fonction supplémentaires peuvent être trouvés dans d'autres espaces de noms.

namespace A {
  struct B { };
  template<int X> void f(B);
}
namespace C {
  template<class T> void f(T t);
}
void g(A::B b) {
  f<3>(b);    //ill-formed: not a function call
  A::f<3>(b); //well-formed
  C::f<3>(b); //ill-formed; argument dependent lookup
              // applies only to unqualified names
  using C::f;
  f<3>(b);    //well-formed because C::f is visible; then
              // A::f is found by argument dependent lookup
}

Autres conseils

Je voudrais affiner réponse peu acceptée. On ne sait pas dans la question de l'OP, mais la partie importante de la norme (cité par Kornel) est ce (Souligné par l'auteur):

Mais quand un modèle de fonction arguments de modèle explicites est utilisé, l'appel n'a pas la forme syntaxique correcte

ce qui est interdit se fonde sur ADL et en utilisant des arguments de modèle explicites. Malheureusement, en utilisant des arguments de modèle non-type nécessite l'aide d'arguments explicites (à moins qu'ils ont des valeurs par défaut).

Ci-dessous un exemple de code montrant ceci:.

[en direct]

#include <string>
#include <utility>

namespace C {
  struct B { };
  template<class T> void f(T t){}
}

void g(C::B b) {
  f(b);           // OK
  //f<C::B>(b);   // ill-formed: not a function call, but only 
                  //  because explicit template argument were used

  std::string s;
  move(s);                      // OK
  //move<std::string&>(s);      // Error, again because 
                                //  explicit template argument were used
  std::move<std::string&>(s);   // Ok
}

int main()
{
 C::B b;
 g(b);
}

Depuis c ++ 20, adl fonctionne aussi très bien avec le modèle de fonction explicite. Voici la proposition: P0846R0: Modèles ADL et fonctions qui ne sont pas visibles :

Au lieu de demander à l'utilisateur d'utiliser le mot-clé de modèle, une révision des règles de consultation a été proposée afin qu'un nom pour lequel une recherche normale produit soit aucun résultat ou trouve une ou plusieurs fonctions et qui est suivi par aa « < » Would traitée comme si un nom de modèle de fonction avait été trouvé et causerait ADL à réaliser.

À l'heure actuelle, seule GCC 9 a implémenter cette fonctionnalité, de sorte que votre exemple peut compiler.

live demo .

Edit: Non, ce n'est pas juste. Voir @ Kornel de réponse.


Je ne suis pas tout à fait sûr, mais après avoir consulté "Le langage C ++ programmation" de Stroustrup Je pense que la section Annexe C 13.8.4 peut être la cause.

Depuis frob est un modèle pourrait éventuellement se spécialiser pour i=0 à un point après que vous l'appelez. Cela signifie que la mise en œuvre se retrouveraient avec deux possibilités de choix qui frob à l'appel comme il semble qu'il peut choisir au moment de l'instanciation ou à la fin du traitement de l'unité de traduction.

Alors, je pense que le problème est que vous pourriez faire

namespace ns {
    struct foo {};
    template<int i> void frob(foo const&) {}
}

int main() {
    ns::foo f;
    frob<0>(f);
    return 0;
}

namespace ns {
    template<> void frob< 0 >(foo const&) { /* Do something different*/ }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top