1

这个问题与之前的问答相关,其中提到了 gcc 的错误报告(据说在 gcc 4.5.0 中已修复),并且涉及嵌套类模板的部分专业化的一些特性。

我的设置是我有一个Base带有嵌套类模板的类,该类模板Inner部分专门用于char(使用虚拟参数技巧,因为在类中不允许显式指定)。

#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于命名空间范围?

但最奇怪的是,当我调用Innerfrom both Baseand的各种偏特化时,我只为之做Derived的偏特化也适用于。intDerivedBase

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>部分特化?

使用 gcc 4.8.0 的在线示例。我正在专门寻找标准中解释这种行为的引用。

4

2 回答 2

1

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

当您struct Inner在范围内编写时Derived,您就是在声明Derived::InnerBase::Inner是一个不同的名称Derived::Inner,因此声明了一个不同的类。不可能专门Base::Inner使用声明Derived::Inner.

当您Derived::Inner在命名空间范围内编写时,名称查找将该名称解析为Base::Inner- 特化都属于同一类:Base::Inner,即使您将它们称为Derived::Inner.

从标准:

[temp.class.spec]

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

于 2013-06-17T18:56:37.133 回答
1

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

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

编译器试图找到最佳匹配类,并且总是选择专用类型而不是默认类型。因此,即使您尝试访问基类型的范围,它仍然是同一个类。

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

于 2013-06-16T11:28:25.770 回答