继承嵌套模板类的专业化

时间:2016-07-06 02:58:53

标签: c++ inheritance language-lawyer inner-classes template-specialization

以下源代码来自: 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错了......

1 个答案:

答案 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 不是声明,但看起来这没有反映在措辞中(标准错误,我想)。