2010-08-22 23 views
4

Le petit exemple montre mon problème suivant:problème par une variable de référence d'un paramètre de modèle

template<class T> struct X 
{ 
    static void xxx(T& x) { } 
    static void xxx(T&& x) { } 
}; 

int main(int argc, char** argv) 
{ 
    int x = 9; 
    X<int>::xxx(x); // OK. 
    X<int&>::xxx(x); // ERROR! 
    return 0; 
} 

Message d'erreur (GCC):

error: ‘static void X::xxx(T&&) [with T = int&]’ cannot be overloaded
error: with ‘static void X::xxx(T&) [with T = int&]’

Pourquoi? T = int& ---> Est T& remplacé par int&& dans static void xxx(T& x)?

Si la réponse à la question est oui, alors:

  • T& n'est pas une référence lvalue et il devient un rvalue référence!
  • Et le code suivant devrait fonctionner:

Mais il n'a pas:

template<class T> struct X 
{ 
    static void xxx(T& x) { } 
}; 

int main(int argc, char** argv) 
{ 
    X<int&>::xxx(2); // ERROR! 
    return 0; 
} 

Message d'erreur (GCC):

error: no matching function for call to ‘X::xxx(int)’
note: candidates are: static void X::xxx(T&) [with T = int&]

Alors T& avec T = int& n'est pas égal à T&& et n'est pas une référence rvalue. mais si ce n'est pas le cas, pourquoi le premier exemple ne fonctionne pas? (C'est un problème récurrent!)


Mais le même problème ne se produit pas pour les types de pointeur:

#include <iostream> 

template<class T> struct X 
{ 
    static void xxx(T* x) { std::cout << **x << std::endl; } 
}; 

int main(int argc, char** argv) 
{ 
    int x = 10; 
    int* xx = &x; 
    X<int*>::xxx(&xx); // OK. call X<int*>::xxx(int**) 
    return 0; 
} 

Pourquoi références sont différentes dans ce comportement?

+1

Ma tête me fait mal. Tant d'esperluettes. –

+3

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&& @ James &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& – GManNickG

Répondre

10

La norme linguistique 11 C++ a une explication de la façon dont cela fonctionne à §8.3.2 [dcl.ref]/6 (reformaté pour une meilleure lisibilité):

If a typedef, a type template-parameter, or a decltype-specifier denotes a type TR that is a reference to a type T ,

  • an attempt to create the type "lvalue reference to cvTR " creates the type "lvalue reference to T "
  • an attempt to create the type "rvalue reference to cvTR " creates the type TR .

Considérons votre exemple (je avez renommé votre T être TR afin qu'il corresponde à la langue ci-dessus):

template<class TR> struct X 
{ 
    static void xxx(TR& x) { } 
    static void xxx(TR&& x) { } 
}; 

Si nous essayons instanciation X avec TR = int& (donc, T = int), les instanciations de xxx sont comme suit:

static void xxx(TR& x) { } --> static void xxx(int& x) { } 
static void xxx(TR&& x) { } --> static void xxx(int& x) { } 

Dans le premier cas, nous essayons de créer une « référence lvalue à TR », qui devient une « référence lvalue à T. » T est int, le type de paramètre devient int&. Dans le deuxième cas, nous essayons de créer une "référence rvalue à TR", qui devient TR, soit int&.

Le type de paramètre est le même pour les deux surcharges, d'où l'erreur.

+1

Je suis environ 70% vous convaincu avez mémorisé les spécifications complètement –

+0

Merci pour exprimer le sens de TR. –

+0

Est-ce la règle qui fait fonctionner 'std :: forward'? C'est-à-dire que chaque programmeur C++ 0x devra le savoir ... :) – UncleBens