2010-02-21 7 views
5

Cette question concerne le fait que mon dernier one. J'essaie de résoudre le problème en utilisant traits<T> et traits<T*>. S'il vous plaît considérer le code suivant.Utiliser des traits en C++

template<typename T> 
struct traits 
{ 
    typedef const T& const_reference; 
}; 

template<typename T> 
struct traits<T*> 
{ 
    typedef const T const_reference; 
}; 

template<typename T> 
class test 
{ 
public: 
    typedef typename traits<T>::const_reference const_reference; 
    test() {} 
    const_reference value() const { 
     return f; 
    } 
private: 
    T f; 
}; 

int main() 
{ 
    const test<foo*> t; 
    const foo* f = t.value(); // error here. cannot convert ‘const foo’ to ‘const foo*’ in initialization 
    return 0; 
} 

Il semble donc que le compilateur ne considère pas les traits de spécialisation pour les pointeurs et prendre type de retour de value() comme const foo plutôt que const foo*. Qu'est-ce que je fais mal ici?

Toute aide serait géniale!

Répondre

2

La spécialisation est utilisée. traits<foo*>::const_referenceestconst foo. Si vous voulez qu'il soit un pointeur, utilisez:

template<typename T> 
struct traits<T*> 
{ 
    typedef const T* const_reference; 
}; 

Avec cela, traits<foo*>::const_reference sera const foo*.

Notez que l'utilisation de T dans la spécialisation traits<T*> est complètement distincte de la T dans le modèle traits. Vous pouvez le renommer:

template<typename U> 
struct traits<U*> 
{ 
    typedef const U* const_reference; 
}; 

et vous aurez la même spécialisation. Cela a plus de sens si vous avez de l'expérience en programmation fonctionnelle. Pour commencer, pensez au template <typename ...> comme introduisant une abstraction, plutôt comme une fonction qui fait abstraction d'une valeur. Il est comme tourner

sum = 0 
for item in [1,2,3]: 
    sum += item 

dans:

function sum(l): 
    sum = 0 
    for item in l: 
     sum += item 
    return sum 

l prend la place de [1,2,3]. Nous pouvons appeler sums d'une autre fonction qui lui-même a un paramètre formel nommé l:

function sumsq(l): 
    return sum(map(lambda x: x*x, l)) 

sumsq 's "l" n'a rien à voir avec sum' "l" s.

Avec les modèles, nous résumons les noms de type plutôt que les valeurs. Autrement dit, nous tourner:

struct traits { 
    typedef const double& const_reference; 
}; 

dans:

template <typename T> 
struct traits { 
    typedef const T& const_reference; 
}; 

Considérons maintenant une spécialisation non-template:

template <> 
struct traits<double*> { 
    typedef const double* const_reference; 
}; 

Ici, il n'y a pas de paramètres de modèle pour la spécialisation, mais vous pouvez Pensez à traits<double*> en appliquant un modèle traits à un double*. Résumé et le double vous avez:

template <typename T> 
struct traits<T*> { 
    typedef const T* const_reference; 
}; 

Ici, le T est un paramètre pour la spécialisation, pas le modèle de base.

+0

Je me sens dump :(Mais, T lui-même est un pointeur ('foo *'). Donc spécifier 'T * 'mènera dans' T ** '? –

+0

No. Dans la spécialisation' traits ', T 'n'est pas un pointeur,' T * 'est un pointeur.Si vous utilisez le même paramètre typename est sans conséquence – outis

+0

OK.Merci.Il est logique maintenant .. –

Questions connexes