【问题标题】:Understanding partial specialization of inherited nested class templates了解继承的嵌套类模板的部分特化
【发布时间】:2013-06-12 12:50:48
【问题描述】:

这个问题与a previous Q&A 相关,其中提到了 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

但最奇怪的是,当我从BaseDerived 调用Inner 的各种偏特化时,我只为Derived 所做的int 的偏特化也适用于@ 987654336@.

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&lt;int&gt;::value 等于false,尽管只有Derived::Inner&lt;int&gt; 是部分特化的?

Online example using gcc 4.8.0。我正在专门寻找标准中解释这种行为的引用。

【问题讨论】:

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


    【解决方案1】:

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

    当你在Derived 的范围内写struct Inner 时,你就是在声明Derived::InnerBase::Inner 是与 Derived::Inner 不同的名称,因此声明了不同的类。不能使用声明 Derived::Inner 的声明来专门化 Base::Inner

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

    来自标准:

    [temp.class.spec]

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

    【讨论】:

    • tnx 为答案 + 标准报价!
    • 我的荣幸!我仍然不确定允许在类之外声明 Derived::Inner 是否合法,或者是编译器错误。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 感谢您对我的第二个问题的回答。这也是我不能在Derived 中部分专门化Inner 的原因吗,即使我可以在Base 中做到这一点?
    • @TemplateRex 因为类不在 Derived 的范围内。它在 Base 的范围内。就像您尝试在派生中创建 Base::SomeFunction() 的实现一样。 (没有覆盖或重载。实际实现)。实现的范围在 Base:: ... 因此如果您尝试在 Derived 类范围内,您将访问的实际范围是:Derived::Base::
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    相关资源
    最近更新 更多