2016-03-29 8 views
0

Ich habe eine base abgeleiteten Typ als Vorlage Parameter. Der folgende Code funktioniert wie erwartet. Instanziierung von base<non_default_impl> verwendet non_default_impl::data_t und base<default_impl> wirft Kompilierungsfehler, da event_data nur eine Vorwärtsdeklaration ist.Mischen von CRTP mit SFINAE

template <typename T> 
struct event_data; 

template<typename T> 
struct tovoid { 
    typedef void type; 
}; 

template <typename T, typename enable = void> 
struct get_data{ 
    typedef event_data<T> type; 
}; 

template <typename T> 
struct get_data<T, typename tovoid<typename T::data_t>::type >{ 
    typedef typename T::data_t type; 
}; 

template <typename T> 
struct base{ 
    typedef typename get_data<T>::type data_type; 

    base(){ 
     data_type(); 
    } 
}; 

struct non_default_impl{ 
    struct data{}; 

    typedef data data_t; 
}; 
struct default_impl{ 

}; 

int main(){ 
    base<non_default_impl> e1; 
    base<default_impl> e2; 
    return 0; 
} 

Aber wenn non_default_impl erbt von base<non_default_impl> SFINAE Ersatz zur Vorwärts Erklärung.

struct non_default_impl: public base<non_default_impl>{ 
    struct data{}; 

    typedef data data_t; 
}; 

int main(){ 
    non_default_impl e1; 
// base<default_impl> e2; 
    return 0; 
} 

prog.cpp: In instantiation of 'base::base() [with T = non_default_impl]':

prog.cpp:28:8: required from here

prog.cpp:24:3: error: invalid use of incomplete type 'base::data_type {aka struct event_data}' data_type();

Wie diese Arbeit zu machen. Ich möchte, wenn die abgeleitete Klasse ein data_t typedef verwendet sonst, dass event_data<derived_type>

https://ideone.com/WOIsn0

Antwort

1

Dies ist eine Einschränkung von CRTP verwenden: zum Zeitpunkt Ihrer base Vorlage ist darauf spezialisiert, für Ihre non_default_impl Klasse, also in seinen Basisklassen Liste , non_default_impl selbst ist noch nicht definiert.

Daher ist jeder Versuch, auf etwas zuzugreifen, das Teil seiner Definition ist, z. B. data_t typedef, fehlgeschlagen.

Da Sie nicht alles erlaubt, was im Inneren non_default_impl ist, ist eine Lösung, einen externen Typ Merkmal zu verwenden, um Ihre data_t zu wählen:

template <class T> 
struct dataType { typedef event_data<T> type; }; 

template <typename T> 
struct base{ 
    typedef typename dataType<T>::type data_type; 

    // ... 
}; 

// Usage 

struct non_default_data {}; 

template <> 
struct dataType<struct non_default_impl> { 
    typedef non_default_data type; 
}; 

struct non_default_impl: public base<non_default_impl> { 
    // ... 
}; 

Beachten Sie, dass Sie nicht non_default_data innerhalb non_default_impl erklären kann, weil es sein muss, Zugänglich von der Typeigenschaft, die von dem CRTP zugänglich sein muss, das noch spezialisiert werden muss, bevor non_default_impl definiert wird.