将 CRTP 与 SFINAE 混合
mixing CRTP with SFINAE
我有一个 base
将派生类型作为模板参数。以下代码按预期工作。 base<non_default_impl>
的实例化使用 non_default_impl::data_t
和 base<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: 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();
如何进行这项工作。我想如果派生的 class 有一个 data_t
typedef 使用否则使用 event_data<derived_type>
这是 CRTP 的警告:当时您的 base
模板专用于您的 non_default_impl
class,即在其基础 classes 列表中,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_impl
内声明 non_default_data
,因为它必须可以从类型特征访问,而类型特征必须可以从 CRTP 访问,而 CRTP 仍然必须在 non_default_impl
已定义。
我有一个 base
将派生类型作为模板参数。以下代码按预期工作。 base<non_default_impl>
的实例化使用 non_default_impl::data_t
和 base<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: 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();
如何进行这项工作。我想如果派生的 class 有一个 data_t
typedef 使用否则使用 event_data<derived_type>
这是 CRTP 的警告:当时您的 base
模板专用于您的 non_default_impl
class,即在其基础 classes 列表中,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_impl
内声明 non_default_data
,因为它必须可以从类型特征访问,而类型特征必须可以从 CRTP 访问,而 CRTP 仍然必须在 non_default_impl
已定义。