méthode modèle correspondant au type dérivé au lieu de la base

J’ai un ensemble d’opérateurs que je dois remplacer pour la modélisation d’expression. Je voudrais que toutes les classes dérivées d’un type de base correspondent au type de base. D’autres choses seraient alors attrapées par un type générique. Malheureusement, le type générique récupère les types dérivés avant le type de base. Pour rendre les choses agréables et déroutantes, tout est basé sur des modèles, y compris certains CRTP. Laissez-moi essayer de vous donner une version plus simple du code:

// Note: 'R' is used for return type template  class Base { // ... }; template  class MultOperation : public Base<MultOperation, R> { // ... }; template  class Terminal : public Base<Terminal, T> { // ... }; // The broken operators: template  MultOperation<Base, Base, typename boost::common_type::type> operator*( Base const& u, Base const& v) { return MultOperation<Base, Base, typename boost::common_type::type>(u, v); } template  MultOperation<Terminal, Base, typename boost::common_type::type> operator*( T1 const& u, Base const& v) { return MultOperation<Terminal, Base, typename boost::common_type::type>(Terminal(u), v); } template  MultOperation<Base, Terminal, typename boost::common_type::type> operator*( Base const& u, T2 const& v) { return MultOperation<Base, Terminal, typename boost::common_type::type>(u, Terminal, v); } 

Maintenant, je ne peux utiliser aucune nouvelle fonctionnalité C ++. (Cela fait partie de certains refactors pour supprimer les anciennes bibliothèques afin que nous puissions passer aux nouvelles normes cpp.) Cependant, je peux utiliser des choses boost. Je pensais que ma réponse pourrait se trouver dans boost::enable_if , mais toutes mes tentatives ont abouti à des impasses. Maintenant, gardez à l’esprit que l’objective est les modèles d’expression, je ne peux donc pas lancer de contenu pour le transfert des données. Ouais … c’est tellement compliqué … J’espère que vous avez un peu de magie dans votre manche.

Version courte de la question: Comment puis-je obtenir (1 * Derived) * Derived pour correspondre à l’ operator(T, Base) pour le premier opérateur, puis à l’ operator(Base, Base) pour le deuxième opérateur? Il correspond actuellement à la première amende, puis le second à l’un des opérateurs génériques de base, T ne prenant pas de conversion et correspondant donc mieux que Base.

Voici un trait qui teste si une classe est une sorte de Base :

 template struct is_some_kind_of_Base { typedef char yes; typedef struct { char _[2]; } no; template static yes test(Base *); static no test(...); static const bool value = (sizeof(test((T*)0)) == sizeof(yes)); }; 

Et contraignez ensuite vos deux derniers operator* comme:

 template  typename boost::disable_if, MultOperation, Base, typename boost::common_type::type> >::type operator*( T1 const& u, Base const& v) { /* ... */ } 

Démo .

Pour empêcher common_type de provoquer une erreur matérielle, nous devons différer son évaluation.

 template  struct make_mult_operation { typedef MultOperation::type> type; }; template  typename boost::disable_if, make_mult_operation, T2, T1, R2> >::type::type operator*( T1 const& u, Base const& v) { /* ... */ } 

Démo .

Je comprends votre question, à savoir que vous souhaitez spécialiser un modèle de classe pour les types dérivés d’un type de base donné. Je vais donner un exemple sans autant de parameters de modèle.

Comme vous l’avez suggéré, l’idée ici est de sélectionner les surcharges via enable_if (j’ai utilisé la classe std::enable_if mais vous pouvez simplement remplacer std:: by boost:: pour vos besoins):

 template struct is_derived_from_base { static constexpr bool first = std::is_base_of, T>::value; static constexpr bool second = std::is_base_of, U>::value; static constexpr bool none = !first && !second; static constexpr bool both = first && second; static constexpr bool only_first = first && !second; static constexpr bool only_second = !first && second; }; template::none>::type > auto operator*(T const& t, U const& u) { std::cout<<"Both T and U are not derived"<(t,u); } template::only_first>::type > auto operator*(Base const& t, U const& u) { std::cout<<"T is derived from Base, U is not derived"<, U>(t,u); } template::only_second>::type > auto operator*(T const& t, Base const& u) { std::cout<<"T is not derived, U is derived from Base"< >(t,u); } template::both>::type > auto operator*(Base const& t, Base const& u) { std::cout<<"T is derived from Base, U is derived from Base"<, Base >(t,u); } 

Pour plus de détails, voir le programme complet ici .