以下源代码来自: Understanding partial specialization of inherited nested class templates
#include <type_traits>
struct Base
{
template<class U, class _ = void> struct Inner: std::true_type {};
template<class _> struct Inner<char, _>: std::false_type {};
};
struct Derived : Base
{
};
template<class _> struct Derived::Inner<int, _>: std::false_type {};
我有一个关于专门继承类的问题,所以我用谷歌搜索,并找出上面的问题。上面问题中的源代码没有编译gcc / clang中的任何问题,但msvc拒绝编译它,发出C2427(参见https://msdn.microsoft.com/en-us/library/10het5hx.aspx)。
我认为上面的情况(专门化非模板类的嵌套模板类)与https://msdn.microsoft.com/en-us/library/10het5hx.aspx中描述的情况(定义模板类的嵌套非模板类)完全不同。
msvc与gcc / clang中哪一个错了?或者只是标准是如此不明确指定这种行为?
我希望msvc错了......
答案 0 :(得分:2)
Clang和GCC是错误的,MSVC和EDG拒绝部分专业化定义是正确的。
部分特化本身就是一个模板,类模板定义是根据类定义在语法上构造的(在语法术语中,类说明符)。在这样的定义中,Derived::Inner<int, _>
是 class-head-name ,Derived::
是嵌套名称说明符。
[9p11]说:
如果 class-head-name 包含嵌套名称说明符, class-specifier 应引用先前声明的类 直接在嵌套名称说明符所在的类或命名空间中 引用,或在内联命名空间集(7.3.1)的元素中 命名空间(即,不仅仅是由a继承或引入 using-declaration ), class-specifier 应出现在 封闭前一个声明的命名空间。 [...]
所以,你必须使用Base::Inner<int, _>
。
如评论中所述,上面的引用也适用于类模板显式特化定义(它们的语法生成也最终使用 class-head-name )。
以下内容并不直接适用于您的示例,但我发现值得一提。
请注意,上面的引用引用了类模板(或显式特化)定义,而不是诸如
之类的声明template<class _> struct Derived::Inner<int, _>;
在语法上,struct Derived::Inner<int, _>
中有一个 elaborated-type-specifier ,上面的段落不适用于此。因此,标准措辞在技术上允许这样的声明。
这似乎不是一种疏忽:上面的措辞是由DR284的决议引入的,其中包括评论:
情绪是在课程定义上应该要求这样做, 但不是一般的详细类型说明符(它们是 引用,而不是声明)。 [...]
建议的决议包括详细说明类型说明符,但这些已从最终措辞中删除。
然而,MSVC和EDG都不接受这样的声明(坦率地说,如果他们这样做,我会发现它令人困惑)。 DR中的注释似乎表明目的是仅允许 elaborated-type-specifiers 不是声明,但看起来这没有反映在措辞中(标准错误,我想)。