2013-08-11 21 views
6

ho provato a trovare un modo per disambiguare questo codice (in fase di compilazione) (da due giorni :-) -> get_value è ambiguo.C++: disambigua questo codice al momento della compilazione?

#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; 
} 

Questa è una soluzione runtime funzionante.

#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; 
} 

C'è una soluzione?

Nota: una possibile via che ho trovato è finita std :: is_base_of <>, ma questo è molto limitata (modello di istanza di profondità)

+0

ti chiamano Get_Value su un oggetto di tipo A, che ha all'interno due oggetti BASE. Quale compilatore dovrebbe scegliere? –

risposta

7

Si tratta di una ricerca del nome ambiguo, che nel caso di più pelli di ereditarietà i nomi nella ricerca. Non arriva nemmeno a controllare quale sovraccarico usare.

È possibile risolvere questo problema aggiungendo il seguente la definizione struct A s':

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

Queste due affermazioni aggiungere il nome get_value da entrambe le classi base ad A, e quindi il compilatore può poi passare con la sua triste vita e controllarli come sovraccarichi.

+0

Fantastico. Grazie – monotomy

+0

@monotomy È possibile spostare la piastra di prova in una classe intermedia che eredita dai vari tipi di 'BASE' in modo lineare, quindi esegue' usando Tail :: get_value' e 'usando Head :: get_value'. Sembrerebbe 'struct A: public BASES < BASE, BASE > {};'. – Yakk

2

Sulla risposta di Atash: Supponendo che non si vuole riscrivere la lista delle classi base nella lista delle basi e nelle utilizzando dichiarazioni, è possibile utilizzare un riferimento indiretto come questo:

#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

Anche bene! Grazie. – monotomy

+0

+1 questo è come ho ottenuto una bella emulazione di mixin in C++ una volta (ma ora uso D> _ <) – user

Problemi correlati