将CRTP与SFINAE混合

时间:2016-03-29 17:18:07

标签: c++ metaprogramming sfinae crtp

我有一个base将派生类型作为模板参数。以下代码按预期工作。 base<non_default_impl>的实例化使用non_default_impl::data_tbase<default_impl>会引发编译错误,因为event_data只是一个前向声明。

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:实例化'base :: base()[用T =   non_default_impl]':

     

prog.cpp:28:8:从这里要求

     

prog.cpp:24:3:错误:无效使用不完整类型   'base :: data_type {aka struct   event_data}'data_type();

如何使这项工作。我希望如果派生类使用data_t typedef,否则使用event_data<derived_type>

https://ideone.com/WOIsn0

1 个答案:

答案 0 :(得分:2)

这是CRTP的一个警告:当您的base模板专门用于您的non_default_impl类时,即在其基类列表中,non_default_impl本身尚未定义。< / p>

因此,任何访问属于其定义的任何内容的尝试(例如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访问,而CRTP仍然必须在{ {1}}已定义。