2013-08-11 4 views
6

J'ai essayé de trouver un moyen de désambiguïser ce code (au moment de la compilation) (puisque deux jours :-) -> get_value est ambugiuous.C++: désambiguise ce code au moment de la compilation?

#include <iostream> 

template <typename T> 
struct type2type {}; 

template<class T, int val> 
struct BASE 
{ 
    static constexpr int get_value (type2type<T>) 
    { 
    return val; 
    } 
}; 

class X {}; 
class Y {}; 

struct A : 
    public BASE< X, 1 >, 
    public BASE< Y, 0 > 
{}; 

int main (int argc, char **argv) 
{ 
    A a {}; 
    std::cout << a.get_value (type2type<X>{}) << std::endl; 
} 

Ceci est une solution d'exécution de travail.

#include <iostream> 

template <typename T> 
struct type2type {}; 

template<class T> 
struct VIRTUAL 
{ 
    int get_value() const 
    { 
    return get_value_from_BASE (type2type<T> {}); 
    } 
private: 
    virtual int get_value_from_BASE (type2type<T>) const = 0; 
}; 

template<class T, int val> 
class BASE : 
    public VIRTUAL<T> 
{ 
    virtual int get_value_from_BASE (type2type<T>) const override 
    { 
    return val; 
    } 
}; 

class X {}; 
class Y {}; 

struct A : 
    public BASE< X, 1 >, 
    public BASE< Y, 0 > 
{}; 

int main (int argc, char **argv) 
{ 
    A a {}; 
    std::cout << a.::VIRTUAL<X>::get_value() << std::endl; 
} 

Existe-t-il une solution?

Note: un moyen possible que je l'ai trouvé est sur std :: is_base_of <>, mais cela est très limité (modèle profondeur de instanciation)

+0

Vous appelez get_value sur un objet de type A, qui contient deux objets BASE. Quel compilateur devrait choisir? –

Répondre

7

Ceci est une recherche de nom ambigu, qui, dans le cas de peaux d'héritage multiple les noms dans la recherche. Il ne vérifie même pas quelle surcharge utiliser.

Vous pouvez résoudre ce problème en ajoutant ce qui suit à la définition de struct A:

using BASE<X,1>::get_value; 
using BASE<Y,0>::get_value; 

Ces deux déclarations ajouter le nom get_value des deux classes de base A, et donc le compilateur peut alors se déplacer avec son morne vie et vérifiez-les comme des surcharges.

+0

Fantastique. Merci – monotomy

+0

@monotomy Vous pouvez déplacer cette liste déroulante vers une classe intermédiaire qui hérite des différents types 'BASE' de façon linéaire, puis fait un' using Tail :: get_value' et 'using Head :: get_value'. Cela ressemblerait à 'struct A: public BASES < BASE, BASE > {};'. – Yakk

2

Miser sur la réponse de Atash: En supposant que vous ne voulez pas retaper la liste des classes de base dans la liste des bases et dans les utilisant déclarations, vous pouvez utiliser une indirection comme ceci:

#include <iostream> 

template <typename T> 
struct type2type {}; 

template<class T, int val> 
struct BASE 
{ 
    static constexpr int get_value (type2type<T> const&) 
    { 
    return val; 
    } 
}; 

class X {}; 
class Y {}; 

template <typename...> struct AUX; 

template <typename Base, typename... Bases> 
struct AUX<Base, Bases...>: Base, AUX<Bases...> { 
    using Base::get_value; 
    using AUX<Bases...>::get_value; 
}; 

template <typename Base> 
struct AUX<Base>: Base { 
    using Base::get_value; 
}; 

struct A : 
    public AUX<BASE< X, 1 >, BASE< Y, 0 > > 
{ 
}; 

int main() 
{ 
    A a {}; 
    std::cout << a.get_value (type2type<X>()) << std::endl; 
} 
+0

Aussi bien! Merci. – monotomy

+0

+1 c'est comme ça que j'ai eu une belle émulation de mixins en C++ une fois (mais maintenant j'utilise D> _ <) – user

Questions connexes