2010-05-05 4 views
1

J'ai une classe de modèle qui définit un sous-type. J'essaie de définir le binaire operator+ en tant que fonction de modèle, mais le compilateur ne peut pas résoudre la version du modèle du operator+.Opérateur + pour un sous-type d'une classe de modèle

#include <iostream> 
template<typename other_type> 
struct c { 
    c(other_type v) : cs(v) {} 
    struct subtype { subtype(other_type v) : val(v) {} other_type val; } cs; 
}; 

template<typename other_type> 
typename c<other_type>::subtype operator+(const typename c<other_type>::subtype& left, 
         const typename c<other_type>::subtype& right) 
{ return typename c<other_type>::subtype(left.val + right.val); } 

// This one works 
// c<int>::subtype operator+(const c<int>::subtype& left, 
//   const c<int>::subtype& right) 
// { return c<int>::subtype(left.val + right.val); } 

int main() 
{ 
    c<int> c1 = 1; 
    c<int> c2 = 2; 
    c<int>::subtype cs3 = c1.cs + c2.cs; 
    std::cerr << cs3.val << std::endl; 
} 

Je pense que la raison est parce que le compilateur (g ++ 4.3) ne peut pas deviner le type de modèle il est donc la recherche de operator+<int> au lieu de operator+.

Pour quelle raison? Quelle solution élégante pouvez-vous suggérer?

+0

La raison est que vous avez nondeduced contexte ici selon C++ standard 14.8.2.4/4. –

Répondre

4

Votre soupçon est correct. Le compilateur ne sait pas ce qu'est other_type. Il ne peut pas le déduire des arguments. De telles formes sont souvent trop lâches pour fournir les informations nécessaires. Considérez

template<typename other_type> 
struct c { 
    c(other_type v) : cs(v) {} 
    typedef int subtype; 
}; 

Si vous deviez passer un int, puis l'une des c<T> cadrerait le projet de loi parce que tous ont le même type int. Dans le cas spécifique des classes imbriquées, cela peut être possible, mais même dans ce cas, ce n'est pas unique. Imaginez que dans c<float> vous pourriez mettre un typedef c<int> subtype;, puis les deux c<float>::subtype et c<int>::subtype répondraient à la facture. De retour à l'époque pré-standard, il existait une liste de problèmes de gabarit que John Spicer a traversés et inventé des solutions raisonnables. C'était un de ces problèmes, et on a constaté que cela n'en valait pas la peine. Vous avez toujours explicitement besoin de fournir l'argument - il n'est jamais déduit.

Vous pouvez changer votre code à ce

template<typename other_type> 
struct subtype { 
    subtype(other_type v) : val(v) {} 
    other_type val; 
}; 

template<typename other_type> 
struct c { 
    c(other_type v) : cs(v) {} 
    subtype<other_type> cs; 
}; 

template<typename other_type> 
subtype<other_type> operator+(const subtype<other_type>& left, 
         const subtype<other_type>& right) 
{ return subtype<other_type>(left.val + right.val); } 

Ou à ce

template<typename other_type> 
struct c { 
    c(other_type v) : cs(v) {} 
    struct subtype { 
    subtype(other_type v) : val(v) {} other_type val; 

    /* note: don't forget friend! */ 
    friend subtype operator+(const subtype& left, 
         const subtype& right) 
    { return subtype(left.val + right.val); } 
    } cs; 
}; 
+0

+1 battu pour cela; c'est un meilleur que le mien allait être de toute façon. –

+0

@Charles, merci. apprécié –

+0

Le second signale une erreur (ombrage other_type) et si je change le nom du type de template il donne la même erreur qu'avant (et il semble que le type de cet ami friend + soit le même que celui d'origine). – baol

Questions connexes