CRTP派生类看似不知道继承类型

时间:2015-07-24 12:41:15

标签: c++ templates c++11 crtp

我有一个结构CRTPBase作为基类,用于奇怪地重现模板模式。它唯一的用途是公开派生类型:

template<typename Derived>
struct CRTPBase {
    using asdf = Derived;
};

现在,我按如下方式使用该类:

struct D : public CRTPBase<D> {
    static_assert(std::is_same<asdf, D>::value, "");
};
到目前为止,没问题。现在,而不是使用&#34;正常&#34;结构,我想使用模板化的结构:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    // the following compiles under VS2012, but not in clang
    static_assert(std::is_same<asdf, DTmpl>::value, "");
};

在VS2012上,上面的编译很好,但clang需要我提到asdf是一种类型:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    static_assert(std::is_same<typename CRTPBase<DTmpl<N>>::asdf, DTmpl>::value, "");
};

现在,我介绍另一个结构Intermediate,其唯一目的是&#34; wrap&#34;给定的基类:

template<typename Base>
struct Intermediate : public Base {};

我的直觉是说Intermediate<CRTPBase<..>>代替CRTPBase<..>将(基本上)没有任何区别。

但是,Visual Studio和clang都编译以下内容:

struct DIntrmd : public Intermediate<CRTPBase<DIntrmd>> {
    static_assert(std::is_same<asdf, DIntrmd>::value, "");
};

Visual Studio和clang都拒绝以下内容:

template<int N>
struct DTmplIntrmd : public Intermediate<CRTPBase<DTmplIntrmd<N>>> {
    static_assert(std::is_same<asdf, DTmplIntrmd>::value, "");
};

同样,我必须明确声明asdf是一种类型,以便编译:

template<int N>
struct DTmplIntrmd : public Intermediate<CRTPBase<DTmplIntrmd<N>>> {
    static_assert(std::is_same<typename Intermediate<CRTPBase<DTmplIntrmd<N>>>::asdf, DTmplIntrmd>::value, "");
};

所以,这是我的问题:关于所描述的情况,哪个是正确的编译器行为?

1 个答案:

答案 0 :(得分:3)

根据[temp.res]

  

模板声明或定义中使用的名称,取决于模板参数   假设不命名类型,除非适用的名称查找找到类型名称或名称是合格的   通过关键字typename

所以在这个例子中:

template<int N>
struct DTmpl : public CRTPBase<DTmpl<N>> {
    // the following compiles under VS2012, but not in clang
    static_assert(std::is_same<asdf, DTmpl>::value, "");
};

asdf是一个依赖于模板参数的名称,因此应该假定它没有命名类型,因为它没有被typename限定。 VS2012编译此代码是错误的,并且clang是正确的。

在你问题的每一个例子中,asdf都不依赖(两个编译器都接受代码)或者它是依赖的(两个编译器都拒绝它)。所有其他行为都是正确的。

有关详情,请参阅Where and why do I have to put the "template" and "typename" keywords?