CRTP派生class貌似不知道继承类型
CRTP derived class seemingly does not know inherited type
我有一个结构 CRTPBase
作为基础 class 用于奇怪的重复模板模式。它的唯一用途是公开派生类型:
template<typename Derived>
struct CRTPBase {
using asdf = Derived;
};
现在,我使用 class 如下:
struct D : public CRTPBase<D> {
static_assert(std::is_same<asdf, D>::value, "");
};
到目前为止,没问题。现在,我不想使用 "normal" 结构,而是使用模板化结构:
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
,其唯一目的是 "wrap" 给定基数 class:
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, "");
};
所以,这是我的问题:对于所描述的情况,编译器的正确行为是什么?
根据[temp.res]
A name used in a template declaration or definition and that is dependent on a template-parameter is
assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified
by the keyword 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?。
我有一个结构 CRTPBase
作为基础 class 用于奇怪的重复模板模式。它的唯一用途是公开派生类型:
template<typename Derived>
struct CRTPBase {
using asdf = Derived;
};
现在,我使用 class 如下:
struct D : public CRTPBase<D> {
static_assert(std::is_same<asdf, D>::value, "");
};
到目前为止,没问题。现在,我不想使用 "normal" 结构,而是使用模板化结构:
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
,其唯一目的是 "wrap" 给定基数 class:
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, "");
};
所以,这是我的问题:对于所描述的情况,编译器的正确行为是什么?
根据[temp.res]
A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword
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?。