2011-12-13 2 views
1

J'ai un modèle de classe qui contient deux fonctions membres similaires:Comment faire pour résoudre ce problème avec const-haut niveau?

template<class T> 
class MyTemplate { 
    // other stuff, then 
    static T* member(T&); //line 100 
    static const T* member(const T&); //line 101 

};

que j'instancier comme ceci:

MyTemplate<int* const> 

et Visual C++ 9 se plaint:

mytemplate.h(101) : error C2535: 'int* MyTemplate<T>::member(T &)' : 
    member function already defined or declared 
with 
[ 
    T=int *const 
] 
mytemplate.h(100) : see declaration of 'MyTemplate::member' 
with 
[ 
    T=int *const 
] 
somefile.cpp(line) : see reference to class template instantiation 
    'MyTemplate<T>' being compiled 
with 
[ 
    T=int *const 
] 

Je certainement besoin des deux versions de member() - une pour référence const et une pour référence non const . Je suppose que le problème a quelque chose avec les qualificatifs const de haut niveau, mais je ne peux pas en déduire comment le résoudre.

Comment puis-je résoudre ce problème afin que j'ai toujours deux versions de member() et le modèle compile?

Répondre

2

Lorsque T est int * const, T est déjà const, donc T& et const T& sont tous les deux int * const.

Ou voulez-vous dire dans ce cas, vous avez besoin de votre classe pour ressembler à:

class MyTemplate_int_p_const{ 
    static int * member (int *&); 
    static int * const member (int * const &); 
}; 

Vous pouvez ajouter à votre modèle principal pour y parvenir:

template<class T> 
class MyTemplate<const T> 
{ 
    static T * member(T&); 
    static const T* member(const T&); 
}; 

En tant que répond à le commentaire de l'OP, si vous ne voulez pas utiliser la spécialisation partielle, vous aurez besoin de type_traits. Il est supporté par C++ 0x, et pour VC++ 9, vous pouvez utiliser boost.

Dans le code suivant, la version non_const de member prendra un dummy_type (un pointeur vers la fonction membre) si T est déjà const. Donc la surcharge non_const n'existerait pas.

#include <type_traits> 
template<class T> 
class MyTemplate { 
    // other stuff, then 

    //void dummy(void); 
    typedef void (*dummy_type)(void); 
    typedef typename std::conditional<std::is_const<T>::value, dummy_type, T>::type T_no_const; 
    typedef typename std::remove_const<T>::type T_remove_const; 
    static T_no_const* member(T_no_const& t) //line 100 
    { 
     if (std::is_same<T, T_no_const>::value) 
     { 
      return member_portal(t); 
     } 
     else 
      return NULL; 
    } 
    static T_no_const* member_portal(dummy_type&){return NULL;}; 
    static T_remove_const* member_portal(T_remove_const&); 
    static const T* member(const T&); //line 101 

}; 


int main() 
{ 
    MyTemplate<int * const> mt; 
    MyTemplate<int *> mtt; 
    return 0; 
} 

Ceci est la première fois que je joue avec type_traits. Il peut passer la compilation sous g ++ 4.5.2 avec C++ 0x activé. Mais je ne l'ai jamais couru. L'idée principale est que lorsque T est const, la version non_const du membre prend un argument de type arbitraire (type qui n'est pas susceptible d'être utilisé ailleurs, et de ne pas être converti implicitement), ainsi la version non_const disparaît. Mais en passant, la logique casse dans l'implémentation de member (comme le type d'argument doit être utilisé, mais n'est pas attendu). Donc, la logique principale de member est de déplacer une autre fonction de member_portal.

+0

Je préfère préfère avoir seulement la version const quand 'T' est const. Est-ce possible? – sharptooth

+0

@sharptooth Bien sûr, supprimez la version non const de 'member' dans la spécialisation partielle. – fefe

+0

Mon modèle est en réalité une centaine de membres - l'idée de spécialisation partielle ne semble pas cool. – sharptooth

2

L'explication donnée par fefe est correcte. Foo const& et Foo const const& vont simplement évaluer le même type, donc votre surcharge de fonction ne fonctionne pas. Dans le cas où votre argument template est const, je suggérerais une spécialisation.

Version A:

template<class T> 
class MyTemplate { 
    static T* member(T&); 
    static const T* member(const T&); 
}; 
template<class T> 
class MyTemplate<T const> { 
    static const T* member(const T&); 
}; 

Version B:

template<class T> 
class MyTemplate_mutableImpl { 
    static T* member(T&); 
}; 
template<class T> 
class MyTemplate_constImpl { 
    static const T* member(const T&); 
}; 
template<class T> 
class MyTemplate : public MyTemplate_mutableImpl<T>, public MyTemplate_constImpl<T> { 
}; 
template<class T> 
class MyTemplate<T const> : public MyTemplate_constImpl<T const> { 
}; 
0

Une solution simple serait de désactiver la fonction si T est const:

#include <boost/mpl/if.hpp> 
#include <boost/type_traits/is_const.hpp> 

template<class T> 
class MyTemplate { 
    static T* member(T&); 
    struct Disabled {}; 
    static const T* member(typename boost::mpl::if_<boost::is_const<T>, Disabled, const T&>::type); 
}; 
Questions connexes