2013-08-11 12 views
6

Próbowałem znaleźć sposób na ujednoznacznienie tego kodu (w czasie kompilacji) (od dwóch dni :-) -> get_value jest ambugiusem.C++: disambiguate ten kod w czasie kompilacji?

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

To działające środowisko wykonawcze.

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

Czy istnieje rozwiązanie?

Uwaga: możliwy sposób, że znalazłem się na std :: is_base_of <>, ale to jest bardzo ograniczona (szablon głębokość instancji)

+0

Państwo zadzwonić get_value na obiekcie typu A, w którym znajdują się dwa obiekty BASE. Który kompilator powinien wybrać? –

Odpowiedz

7

To jest niejednoznaczna nazwa odnośnika, który w przypadku wielu skór dziedziczenia nazwiska w wyszukiwaniu. Nie ma nawet możliwości sprawdzenia, którego przeciążenia należy użyć.

Można rozwiązać ten problem poprzez dodanie następujących definicji struct A „s:

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

Te dwa stwierdzenia dodać nazwę get_value z obu klas bazowych do A, a więc kompilator może następnie przenieść się z jego ponury życie i sprawdź je jako przeciążenia.

+0

Fantastyczne. Dzięki – monotomy

+0

@monotomia Możesz przenieść ten zestaw znaków do klasy pośredniej, która dziedziczy po różnych typach 'BASE' w sposób liniowy, następnie używa' Tail :: get_value' i 'using Head :: get_value'. Wyglądałoby to jak "struct A: public BASES < BASE, BASE > {};'. – Yakk

2

Opierając się na odpowiedź Atash za: Zakładając, że nie chcesz wpisywać listę klas bazowych na liście baz oraz w wykorzystaniem deklaracji, można użyć zadnie takiego:

#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

Dobrze! Dzięki. – monotomy

+0

+1 W ten sposób uzyskałem ładną emulację mixinów w C++ (ale teraz używam D> _ <) – user

Powiązane problemy