我有一个结构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, "");
};
所以,这是我的问题:关于所描述的情况,哪个是正确的编译器行为?
答案 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?。