2010-06-01 2 views
70

Quelle partie de la spécification C++ limite la recherche dépendant d'un argument à la recherche de modèles de fonction dans l'ensemble des espaces de noms associés? En d'autres termes, pourquoi le dernier appel main ci-dessous ne parvient pas à compiler?Pourquoi ADL ne trouve-t-il pas de modèles de fonction?

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. 
} 
+0

Est-ce que cela signifie que vous vous attendez à travailler FRAB() sans écrire ns :: FRAB()? – Simon

+0

Oui, à la manière d'une fonction non-template. – Hugh

+0

FYI le code ci-dessus échoue également dans Comeau: http://www.comeaucomputing.com/tryitout/ - en ajoutant 'using namespace ns;' ou la qualification 'ns ::' passe la compilation. C'est une bonne question. – fbrereto

Répondre

74

Cette partie explique:

C++ standard 03 14.8.1.6:

[Note: Pour les noms simples de fonction, la recherche en fonction des arguments (3.4.2) applique même lorsque le nom de la fonction n'est pas visible dans la portée de l'appel. C'est parce que l'appel a toujours la forme syntaxique d'un appel de fonction (3.4.1). Mais lorsqu'un modèle de fonction avec des arguments de modèle explicites est utilisé, l'appel n'a pas la forme syntaxique correcte à moins qu'un modèle de fonction avec ce nom soit visible au moment de l'appel. Si aucun nom n'est visible, l'appel n'est pas syntaxiquement bien formé et la recherche dépendant des arguments ne s'applique pas. Si un tel nom est visible, la recherche dépendante de l'argument s'applique et 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 
} 
+4

+1 Bonne réponse. – fbrereto

+0

Excellent - merci. – Hugh

+0

Ah, je ne pouvais pas trouver cette référence :) +1 –

0

Edit: Non, ce n'est pas juste. Voir @Kornel's answer.


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

Depuis frob est un modèle que l'on pourrait concevoir se spécialiser pour i=0 à un point après l'avoir appelé. Cela signifie que la mise en œuvre serait laissée avec deux façons possibles de choisir frob pour appeler comme il semble qu'il peut choisir au point d'instanciation ou à la fin du traitement de l'unité de traduction.

Donc, 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*/ } 
} 
+0

Non, prenez les espaces de noms et vous avez toujours votre problème, n'est-ce pas? La spécialisation après utilisation est un problème normal en C++, le formulaire spécialisé n'est pas utilisé s'il est déclaré après. –

+0

@Kornel: Ah oui, ça donne une erreur différente, une de plus en ligne avec ce que j'ai décrit. Assez juste, merci de le signaler. – Troubadour

3

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 avec arguments de modèle explicites est utilisé, l'appel n'a pas la forme syntaxique correcte

alors ce qui est interdit dépend de l'ADL et de l'utilisation d'arguments de modèle explicites. Malheureusement, l'utilisation d'arguments de modèle non-typés nécessite l'utilisation d'arguments explicites (sauf s'ils ont des valeurs par défaut).

est un exemple de code ci-dessous montrant ce

.:

[live]

#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); 
} 
Questions connexes