C++ CRTP与SFINAE的混合

C++ CRTP与SFINAE的混合,c++,metaprogramming,sfinae,crtp,C++,Metaprogramming,Sfinae,Crtp,我有一个base将派生类型作为模板参数。以下代码按预期工作。base的实例化使用non\u default\u impl::data\u t和base引发编译错误,因为event\u data只是一个转发声明 template <typename T> struct event_data; template<typename T> struct tovoid { typedef void type; }; template <typename T, ty

我有一个
base
将派生类型作为模板参数。以下代码按预期工作。
base
的实例化使用
non\u default\u impl::data\u t
base
引发编译错误,因为
event\u 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;
}
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()[with T= 非默认值“\u impl]”:

程序cpp:28:8:从这里开始需要

程序cpp:24:3:错误:不完整类型的使用无效 'base::data_type{aka struct 事件_data}'数据_类型()

如何做到这一点。如果派生类有
data\u t
typedef,则使用
event\u data


这是CRTP的一个警告:当您的
基本
模板专门用于您的
非默认执行
类时,即在其基类列表中,
非默认执行
本身尚未定义

因此,任何访问属于其定义一部分的内容(例如
data\u t
typedef)的尝试都会失败

由于不能使用
非默认\u impl
中的任何内容,因此解决方案是使用外部类型特征来选择
数据:

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> {
    // ...
};
模板
结构数据类型{typedef event_data type;};
模板
结构基{
typedef typename dataType::type data_type;
// ...
};
//用法
结构非默认数据{};
模板
结构数据类型{
typedef非默认数据类型;
};
结构非默认值默认值:公共基{
// ...
};
请注意,您不能在
非默认\u impl
中声明
非默认\u数据,因为它必须可以从type trait访问,而type trait必须可以从CRTP访问,在定义
非默认\u impl
之前,还必须对其进行专门化