将CRTP与SFINAE混合 [英] mixing CRTP with SFINAE

查看:92
本文介绍了将CRTP与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_implbase<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结构 event_data}'data_type();

如何进行这项工作.我想要派生类是否使用data_t typedef,否则使用event_data<derived_type>

https://ideone.com/WOIsn0

解决方案

这是CRTP的一个警告:在您的base模板专门用于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之前仍必须进行特殊处理. /p>

I have a base taking derived type as template parameter. The following code works as expected. instantiation of base<non_default_impl> uses non_default_impl::data_t and base<default_impl> throws compilation error because event_data is only a forward declaration.

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;
}

But when non_default_impl inherits from base<non_default_impl> SFINAE substitutes to the forward declaration.

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

How to make this work. I want if the derived class have a data_t typedef use that otherwise use event_data<derived_type>

https://ideone.com/WOIsn0

解决方案

This is a caveat of CRTP : at the time your base template is specialized for your non_default_impl class, i.e in its base classes list, non_default_impl itself is not defined yet.

Thus, any attempt to access anything that is part of its definition, for example the data_t typedef, fails.

Since you cannot use anything that is inside non_default_impl, a solution is to use an external type trait to choose your 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> {
    // ...
};

Note that you can't declare non_default_data inside non_default_impl, since it must be accessible from the type trait, which must be accessible from the CRTP, which still has to be specialized before non_default_impl is defined.

这篇关于将CRTP与SFINAE混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆