当前位置: 首页 > 知识库问答 >
问题:

无法理解非特化类模板成员显式特化声明的规则

卫弘义
2023-03-14

在最新的c标准中,非专业化类模板成员的显式专业化声明规则如下:

在类模板的成员或出现在命名空间作用域中的成员模板的显式专门化声明中,该成员模板及其某些封闭类模板可能仍然未被专门化,但如果其封闭类模板也未被显式专门化,则该声明不应显式专门化该类成员模板。在这种明确的专门化声明中,应提供关键字模板和模板参数列表,而不是模板

老实说,我对这一段有很多困惑。请考虑下面这个规则中的例子。

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};
template <class Y> 
template <>
void A<Y>::B<double>::mf2() { }   // error: B<double> is specialized but  
                                  // its enclosing class template A is not

正如评论所说,成员mf2的显式特化声明是格式错误的,但是,我不明白为什么通过这个规则这个分隔符是格式错误的。我的原因是粗体的措辞,它说如果它的封闭类模板也没有显式特化,则声明不应显式特化类成员模板。但是,在这个例子中,声明是mf2的显式特化,它不是类成员模板,而是类模板的成员。所以严格来说,它不符合异常的条件,为什么声明格式错误?我觉得这一段不清楚。所以进一步挖掘,我发现了有缺陷的报告,即CWG529。

上面说:

在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板及其一些封闭的类模板可能保持非特化,即相应的模板前缀可以指定模板参数列表而不是模板

我想了想,仍然觉得建议不足以解释这些情况,例如:

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};

template<>
template <class T> 
void A<int>::B<T>::mf2(){}

首先,mf2不是模板特化,但是模板idB

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};

template<>
template <class T> 
template <class U> 
void A<int>::B<T>::mf1(U){}

mf1是模板名称,但不是模板id(即模板专用化)

那么,在考虑了这些格式错误的例子之后,IMHO,这个经过修改的句子是这个规则的意图吗?

在命名空间范围中出现的类模板或成员模板的成员的显式专门化声明中,该成员模板及其一些封闭类模板可能仍然未专门化。在这种明确的专门化声明中,应提供关键字模板和模板参数列表,而不是模板

template <class T1> class A {
  template<class T2> class B {
    template<class T3> 
    void mf1(T3);
    void mf2();
  };
};

template<>   // explicit specialization for `B`
template<class T>
class A<int>::B{
   template<class U>
   void mf1(U);
};

template<>
template<class T>
template <class U> 
void A<int>::B<T>::mf1(U){}

虽然B,但这个示例的格式不正确


共有1个答案

全彬
2023-03-14

规则[temp.expl.spec]/p16递归地应用,它简单地说,任何东西都不能被专门化,除非通向它的整个链也被专门化。

我们甚至不能使用mf2,因为不可能专门针对每个可能的A

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};

template <class Y> 
template <>
void A<Y>::B<double>::mf2() { }  // Not OK - can't specialize B for every possible A

template <> 
template <>
void A<int>::B<double>::mf2() { }  // OK - full specialization
template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};

template <>
template <class T> 
void A<int>::B<T>::mf2(){}

同样的故事:不能为每一个可能的A专门化mf2

最后一个带有专门A的示例

template <class T1> class A {
template <class T2> class B {
    template<class T3> 
    void mf1(T3);
    void mf2();
};
};

template <>
template <class T>
class A<int>::B {   // explicit specialization for `B`
    template<class U>
    void mf1(U);
};

template <>
template <class T>
template <class U> 
void A<int>::B<T>::mf1(U){} // OK (not a specialization, but an out-of-line definition)

template <>
template <class T>
template <> 
void A<int>::B<T>::mf1(double){} // Not OK again, the entire chain must be specialized

template <>
template <>
template <> 
void A<int>::B<double>::mf1(double){} // OK - full specialization

CWG 529试图解决[temp.expl.spec]/p16中的措辞令人困惑的事实,因为它谈论嵌套类的“专门化”,而实际上没有声明此类专门化。IMHO,CWG 529没有承认在每一个筑巢水平上都有专门化,只是这是假设。举第一个例子:

template <class T1> class A {
  template<class T2> class B {
    template<class T3> void mf1(T3);
    void mf2();
  };
};

template <class Y> 
template <>
void A<Y>::B<double>::mf2() { }

没有模板

 类似资料:
  • 是否有人知道此显式特化是否有效: clang 主干 (12/3/2013) 给出以下错误: f:...\test.cpp:36:20: 错误: 从类 'O' 中出线定义 “Fun” 没有定义 1生成错误。 任何来自标准的支持参考来证明你的答案将不胜感激! 注意:我有点惊讶这是一个错误——我认为应该为任何以< code >开始实例化“Fun”的模板参数族选择专门化 这是一个叮当的错误还是我期望中的错

  • 我有一个问题,我想在下面的代码中专门化模板类的模板成员函数。这个问题的答案是模板类成员函数的显式特化,这似乎表明它无法完成。这是正确的吗,如果是这样,我可以使用任何解决方法,以便在编译时通过内联inc函数进行扩展? 非常感谢! g吐槽道: test2.cpp:32:13: 错误: 非命名空间作用域中的显式专用化 'struct IdxIterator' test2.cpp:32:25: 错误: 非

  • [dcl.spec.auto]/14国[强调我的]: 显式实例化声明不会导致使用占位符类型声明的实体的实例化,但也不会阻止根据需要对该实体进行实例化以确定其类型。[示例: -结束示例] 和[temp.explicat]/11声明[强调我的]: 现在,考虑我们是否在类模板中的friend声明中定义了friend函数: 如果在同一翻译单元中实例化了的多个专门化,则将违反[basic.def.odr]/

  • 假设我有一个模板类Foo,具有两个模板参数和一个模板成员函数。 我想在模板类是部分专门化的情况下进行成员函数专门化,但以下代码被g编译失败 G说: 错误:在' 模板 我试过了 而g抱怨更多 能不能可能,怎么做?

  • 2.2.1 根据类型执行代码 前一节的示例提出了一个要求:需要做出根据类型执行不同代码。要达成这一目的,模板并不是唯一的途径。比如之前我们所说的重载。如果把眼界放宽一些,虚函数也是根据类型执行代码的例子。此外,在C语言时代,也会有一些技法来达到这个目的,比如下面这个例子,我们需要对两个浮点做加法, 或者对两个整数做乘法: struct Variant { union { int x