2016-03-29 2 views
0

У меня есть base, берущий производный тип в качестве параметра шаблона. Следующий код работает так, как ожидалось. экземпляр base<non_default_impl> использует non_default_impl::data_t и base<default_impl> генерирует ошибку компиляции, потому что event_data является только декларацией.смешивание CRTP с 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; 
} 

non_default_impl Но когда наследуется от base<non_default_impl> SFINAE заменителей к передней декларации.

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();

Как сделать эту работу. Я хочу, если производный класс имеет data_t ЬурейиЕ использовать что в противном случае использовать event_data<derived_type>

https://ideone.com/WOIsn0

ответ

1

Это предостережение CRTP: в то время вашего base шаблон специализирован для non_default_impl класса, то есть в списке базовых классов , non_default_impl сам пока не определен.

Таким образом, любая попытка получить доступ к чему-либо, что является частью его определения, например data_t typedef, терпит неудачу.

Поскольку вы не можете ничего, что находится внутри non_default_impl использования, решение использовать внешний тип признак, чтобы выбрать data_t:

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> { 
    // ... 
}; 

Обратите внимание, что вы не можете объявить non_default_data внутри non_default_impl, так как оно должно быть доступный из черты типа, который должен быть доступен из CRTP, который все еще должен быть специализированным до того, как будет определено значение non_default_impl.

Смежные вопросы