【问题标题】:A confusion about explicit specialization for member of class template关于类模板成员的显式特化的混淆
【发布时间】:2020-11-17 17:37:15
【问题描述】:
template<class T> struct A {
  struct B { };
  template<class U> struct C { 
      void show();
  };
};

template<>
template<>
void A<int>::C<int>::show(){  //#1

}

int main(){

}

考虑上面的code,在#1,它是成员类模板成员的显式特化定义。将对其应用一些规则,如下所示:

temp.expl.spec#5

显式特化类的成员不会从类模板的成员声明中隐式实例化;相反,如果需要定义类模板特化的成员,则其自身应被显式定义。 在这种情况下,类模板显式特化的定义应在定义成员的点的范围内。显式特化类的定义与生成的特化的定义无关。也就是说,它的成员不必与生成的特化的成员具有相同的名称、类型等。显式特化类模板的成员以与普通类成员相同的方式定义,并且不使用 template 语法。定义显式特化成员类的成员时也是如此。但是,template 用于定义明确专门化的成员类模板的成员,该模板专门化为类模板。

首先,explicitly specialized class 是什么?它是否指具有明确专业化声明的实体?好像不是这个意思,请看Explicitly specialized class部分的例子

template<> template<> class A<int>::B<double>;

根据该示例,成员显式特化中的A&lt;int&gt; 可以称为explicitly specialized class。那么,在我的第一个示例中,A&lt;int&gt;C&lt;int&gt; 都是 explicitly specialized class?我不知道。我觉得这句话explicitly specialized class 在这部分不太清楚。

请注意强调部分,这意味着封闭类模板显式特化应与其成员的显式特化定义出现在同一范围内。该成员是在全局范围内定义的,但对于出现在全局范围内的 A&lt;int&gt;C&lt;int&gt; 没有任何明确的专业化定义。这个怎么解释?

顺便说一句,作为一个相反的例子:

template<class T> struct A {
  struct B { };
  template<class U> struct C { 
      void show();
  };
};

template<>
template<typename U>
struct A<int>::C{  //#2
    void show();
};

template<>
template<typename U>
void A<int>::C<U>::show(){  //#3

}

int main(){

}

为什么在#3 之前需要对类模板C 进行显式特化,这两个示例有什么区别?

显式特化类

本节中“显式特化类”这一短语不清楚,

temp.expl.spec#15

成员或成员模板可以嵌套在许多封闭类模板中。在此类成员的显式特化中,成员声明之前应为 显式特化的每个封闭类模板的模板。

[ Example:  
template<class T1> class A {
  template<class T2> class B {
    void mf();
  };
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
— end example ]  

explicitly specialized class 是什么意思,它是指具有明确专业化声明或其他东西的实体吗?在上面的例子中,A&lt;int&gt; 似乎没有明确的特化。

【问题讨论】:

  • 你为什么要引用那一段?您的代码中显式专门化的类在哪里?
  • 缺少几件事来使该引用具有相关性。它说如果你有一个明确的类模板特化(你没有)并且该特化的成员需要一个定义,那么类模板必须在成员定义的范围内(不在同一范围内,只是可见)。
  • 你的代码已经被上一段覆盖了。
  • @LanguageLawyer explicitly specialized在这部分的写法不清楚,请看temp.expl.spec#15,示例中不包含任何enclosing class template that is explicitly specialized
  • @jackX 我想是wg21.link/cwg529

标签: c++ templates language-lawyer


【解决方案1】:

那里没有混淆,您必须根据它们的语法结构解析这些语句(C++ 和英语)。源代码是用人类可以理解的语言对程序的描述。编程语言是人类合作的工具。

CWG529 删除了通过更改措辞来解释模板 ID 的顺序和内容来直观理解的需要。

在这里,您使用模板参数 T 声明了类 A 的模板,其中包含类 B 和使用模板参数 U 的模板类 C 的嵌套声明,其中包含方法 show()

template<class T> struct A {
  struct B { };
  template<class U> struct C { 
      void show();
  };
};

您在这里声明,对于带有 T = int 的显式专用模板类 A(需要先声明它),有一个模板类 C 包含方法 show()

template<>
template<typename U>
struct A<int>::C{  //#2
    void show();
};

这个声明与前面的声明并不矛盾,但因为它是 A 类的特化,它可能会扩展它!你可以这样做:

template<>
template<typename U>
struct A<int>::C{  //#4
    void hide();
};

这意味着对于任何带有T=int 的A,都有一个模板类C 具有成员hide()。但是其他 A 将具有模板类 C,其成员为 show()。之前的声明做了什么,它消除了对这个 A 专业化 C 内容的任何怀疑。

现在这只为A&lt;int&gt;中包含的所有C定义成员函数show()

template<>
template<typename U>
void A<int>::C<U>::show(){  //#3

}

这里没有明确的 C 特化,它是 show() 的封闭类。成员 id show() 前面是一个非专业化的模板 ID template&lt;typename U&gt; ... C&lt;U&gt;。只有成员函数的定义,但它需要该模板 C 的可见声明 - #2 部分。可见性可以通过多种方式获得,“范围”是对其的概括描述。

省略第 2 部分相当于写作的语义:

class C;

void C::show() { // ill-formed - C is an incomplete type.
}

我们会知道所有的 A 都包含一些 C 类,但我们在专门的 A&lt;int&gt; 中没有针对特定 C 的完整定义(可能会有所不同)。

这个语句实际上声明了专业化C&lt;int&gt;嵌套在​​专业化A&lt;int&gt;中包含show()

template<>
template<>
void A<int>::C<int>::show(){  //#1

}

任何可能的矛盾、歧义或不确定性(除了未定义的行为)都会导致格式错误的代码,并且规则旨在形成应检查代码的限制框架。如果没有#2,则#3 之后可能会跟着#4,那么#3 语句将变为非法,因此被视为非法。 #2 和 #4 同时是同一事物的两个定义,如果它们存在于同一单元中,也会导致格式错误的代码,或者如果它们存在于程序中的不同单元中,则会导致未定义的行为。

【讨论】:

  • 您似乎没有从 LanguageLawyer 角度解释这些代码。实际上,在 [temp.expl.spec] 部分中,explicit specialized 这句话并不清楚,wg21.link/cwg529 对此进行了澄清。
  • 为什么Omitting part #2 would be a semantic equivalent of writing...?类模板C 的定义已在您的第一个代码中定义。为什么它不完整?作为一个相反的例子,为什么我不需要在我的例子中为void A&lt;int&gt;::C&lt;int&gt;::show() 定义template&lt;&gt; template&lt;typename U&gt; struct A&lt;int&gt;::C{ //#2 void show(); };
  • @jackX 是类模板 A 中类 C 的定义。但是您试图为嵌套在明确专门化的 A&lt;int&gt; 中的类模板 C 定义成员,而不定义该类模板,它不是类模板成员的特化A&lt;int&gt;:Cvoid A&lt;int&gt;::C&lt;int&gt;::show() 变体是 temp.expl.spec#15 允许的(并且 cwg529 消除了对其含义的直观理解因素),因为它是一种专业化
  • @jackX 与void foo(class C&amp; a)void foo(C&amp; a) 之间的区别相似吗?首先也前向声明类 C。模板不能被前向声明,但temp.expl.spec#15 明确允许声明存在这种特化。在有问题的变体中,它是未知的。据我们所知,A&lt;int&gt; 可能是 template&lt;&gt; A&lt;int&gt; {}; - 一个空类,或者 A&lt;int&gt;::C 可以是一个空类。
  • 没有。这种情况void A&lt;int&gt;::C&lt;int&gt;::show()temp.expl.spec#4 允许,其中专业化A&lt;int&gt;C&lt;int&gt; 都导致implicitly instantiation。并且成员void A&lt;int&gt;::C&lt;U&gt;::show()的显式特化应遵循temp.expl.spec#5规则,即封闭类模板C的显式特化声明应出现在定义成员的范围内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 2019-01-21
  • 2015-03-04
  • 2018-01-13
  • 2021-01-14
相关资源
最近更新 更多