了解继承的嵌套类模板的部分特化

时间:2013-06-16 11:21:02

标签: c++ templates language-lawyer nested-class partial-specialization

这个问题与a previous Q&A有关,其中提到了gcc的错误报告(据说在gcc 4.5.0中已修复),并且涉及嵌套类模板的部分特化的一些特性。

我的设置是我有一个类Base,它有一个嵌套的类模板Inner,它部分专门用于char(使用伪参数技巧,因为不允许显式specigeztion -class)。

#include <type_traits>
#include <iostream>
#include <ios>

struct Base
{
    // dummy template parameter...
    template<class U, class _ = void> struct Inner: std::true_type {};

    // ... to allow in-class partial specialization
    template<class _> struct Inner<char, _>: std::false_type {};
};

我现在定义一个Derived类,我进一步想要专门化Inner,由于某些奇怪的原因不能在课堂上完成(即使它仍然是部分特化)。

struct Derived
:
    Base
{
    // cannot partially specialize Inner inside Derived...
    //template<class _>
    //struct Inner<int, _>: std::false_type {};
};

// ... but specializing Derived::Inner at namespace scope, also specializes it for Base::Inner
template<class _> struct Derived::Inner<int, _>: std::false_type {};

第一个问题:为什么我必须在命名空间范围内部分专门化Derived::Inner

但最奇怪的是,当我从InnerBase调用Derived的各种部分特化时,int的部分特化我只是为了Derived也适用于Base

int main()
{
    std::cout << std::boolalpha << Base::Inner<float>::value << "\n";    
    std::cout << std::boolalpha << Derived::Inner<float>::value << "\n";    

    std::cout << std::boolalpha << Base::Inner<char>::value << "\n";    
    std::cout << std::boolalpha << Derived::Inner<char>::value << "\n";    

    std::cout << std::boolalpha << Base::Inner<int>::value << "\n";      // huh???
    std::cout << std::boolalpha << Derived::Inner<int>::value << "\n";   // OK 
}

第二个问题:为什么Base::Inner<int>::value等于false,即使Derived::Inner<int>仅部分专业化了?

Online example using gcc 4.8.0。我特意在寻找解释这种行为的标准引用。

2 个答案:

答案 0 :(得分:1)

专业模板不是多态性的一部分。

你实际上在声明一种类型。因此,任何可以看到带有模板特化实现的派生头文件的编译单元都将对嵌套模板类使用该特化。

编译器尝试查找最佳匹配类,并始终选择超过默认值的专用类型。因此,即使您尝试访问基类型的范围,它仍然是同一类。

如果您在代码的任何其他部分专门化模板类,则会发生同样的事情。编译器将选择最佳匹配的专业化,如果有非专业化,则采用“默认”。

答案 1 :(得分:1)

部分专业化必须重新声明与其提供替代定义的主要模板相同的名称。

当您在struct Inner范围内撰写Derived时,您宣布Derived::InnerBase::Inner是与Derived::Inner不同的名称,因此声明了另一个类。无法使用声明Base::Inner的声明对Derived::Inner进行专门化。

当您在命名空间范围内编写Derived::Inner时,名称查找会将该名称解析为Base::Inner - 这些专业化都属于同一类:Base::Inner,即使您将它们称为{ {1}}。

来自标准:

  

[temp.class.spec]

     

当特殊化中的参数与部分特化中给出的参数匹配时,类模板的部分特化提供了模板的替代定义,而不是主定义。