中译中:将Cppreference上的部分词条再译为中文

CPP/语言/重载决议

在这一页面,有着以下的词条:

构造函数候选的额外规则:
在构造类型 D 的对象时,如果满足以下所有条件,那么从类类型 C 继承的首个形参类型是“到 P 的引用”的构造函数(包括从模板实例化的此类构造函数)会从候选函数集合排除:

  • 实参列表只有一个实参
  • C 引用关联于 P
  • P 引用关联与 D

该词条比较难以理解,牵扯的概念较多,对于首次查询该词条的用户来说,难以模拟情景。但我们翻看C++标准草案,不难发现,这一部分的原文来自:

[n4849]
12.4.1 Candidate functions and argument lists [over.match.funcs]

8 … A constructor inherited from class type C (11.10.3) that has a first parameter of type “reference to cv1 P” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D if the argument list has exactly one argument and C is reference-related to P and P is reference-related to D.

同时,标准草案给出了示例:

struct A {
A();                              // #1
A(A &&);                          // #2
template<typename T> A(T &&);     // #3
};
struct B : A {
using A::A;
B(const B &);                     // #4
B(B &&) = default;                // #5, implicitly deleted
struct X { X(X &&) = delete; } x;
};
extern B b1;
B b2 = static_cast<B&&>(b1);      // calls #4: #1 is not viable, #2, #3, and #5 are not candidates
struct C { operator B&&(); };
B b3 = C();                       // calls #4

直观地解释了上述词条。当然,草案中的示例代码涵盖的情况较多,我们再简化代码,方便理解,举一反三即可:

struct A {
  A() { }
  A(const A&) {
    std::cout << "A" << std::endl;
  }
};
struct B : A {
  using A::A;
};
B b { B{} };

结果这个程序不会输出"A"。

现在我们来逐步分析:

  • 类型B(对应类型D)继承类型A(对应类型C),所以类型A引用关联于B
  • 类型B从类型A继承了两个构造函数:A::A()A::A(const A&)
  • 并且构造函数A::A(const A&)的首个形参类型为到A(对应类型P)的引用,而A类型显然和自身类型(对应类型C)相似,自身类型引用关联于类型A(对应类型C引用关联于类型P)
  • 在构造对象b时,实参列表只有B{}这一个实参,到这里,符合了词条中描述的三个条件
  • 因此,在选择构造函数时,A::A(const A&)不会作为候选函数,而会选择类型B的隐式声明的移动构造函数。
注释[1]:引用关联于

类型T1T2的无cv限定类型U1U2,如果U1U2相似,或者U1U2的基类,则T1引用关联于T2

CPP/语言/隐式转换

在该页面以及本文中,出现了一个概念:“相似类型”

它在cppreference上的描述如下:

非正式地说,忽略顶层 cv 限定性,如果两个类型符合下列条件,那么它们相似:

  • 它们是同一类型;或
  • 它们都是指针,且被指向的类型相似;或
  • 它们都是指向相同类的成员指针,且被指向的成员类型相似;或
  • 它们都是数组,且数组元素类型相似。

正式地说,类型的相似性基于它们的限定性分解进行定义。
类型 T 的限定性分解 是包含组分 cv_i 和 P_i 的序列,它们对于某些非负 n 可以将 T 分解为 “cv_0 P_0 cv_1 P_1 … cv_n−1 P_n−1 cv_n U”,其中:

每个 cv_i 都是一个可以包含 constvolatile 的集合。

每个 P_i 都是以下之一:

  • “指向【某类型】的指针”。
  • “指向类 C_i 的【某类型】成员的指针”。
  • “包含 N_i 个【某类型】元素的数组”。
  • “包含【某类型】元素且边界未知的数组”。

对于类型 T1 和 T2,如果它们各自有一个限定性分解,使得这两个限定性分解满足以下所有条件,那么这两个类型相似:

  • 它们具有相同的 n。
  • 它们的 U 指代的类型相同。
  • 所有的 i 对应的每对 P_i 组分都各自相同

对于相似类型的非正式解释是比较简单易懂的(或者说,就是对正式解释的总结),这里不再赘述。然而,其正式解释却让人摸不着头脑,难以读懂,这里我们结合cppreference上的示例进行分析。

using T1 = const int* volatile *;

using T2 = int** const;
T1与T2相似。

就上述案例而言,我们用限定性分解的方式来进行解释。

在此之前,我们先了解限定性分解(cv-decomposition)中的三个要素:n, cv_iP_iU

  • 限定性分解中的n,代表了你要对这个类型打算分解几层
  • cv_i,代表了所在的这一层的类型的cv限定类型
  • P_i,代表了所在层的指针类型(U则代表最后一层的类型)

所谓限定性分解,就是将多级指针(从外向内)逐层分解(n次),得到每一层指针的类型和其cv限定符。

因此,上述案例中,我们进行限定性分解得到:

对T1而言:

  • n=0时,U是一个指针,cv_0=空,指向一个volatile指针,这个volatile指针指向const int
  • n=1时,P_0是和上文U类型相同的指针,cv_0=空
    • U是一个指针,cv_1=volatile,指向const int
  • n=2时,P_0是和上文U类型相同的指针,cv_0=空
    • P_1是一个指针,cv_1=volatile,指向const int
    • U是int,cv_2=const

对T2而言:

  • n=0时,U是一个指针,cv_0=const,指向一个指针,这个指针指向int
  • n=1时,P_0是一个指针,cv_0=const
    • U是一个指针,cv_1=空,指向int
  • n=2时,P_0是一个指针,cv_0=const
    • P_1是一个指针,cv_1=空,指向int
    • U是int,cv_2=空

对于T1和T2,它们各自拥有三个限定性分解,对于前两个限定性分解而言,其类型U不相同,但对于n=2时的限定性分解而言:

  • 其U类型都是int
  • n相同
  • 每一对P_0、P_1都是指向某类型的指针(或者说,组分相同)

因此,T1和T2满足相似的条件,两类型相似。

总结:遇到相似性难以判定的情况时,如果要采用限定性分解判定相似类型,应逐层剖析指针,提取cv限定,比较最长限定分解的情况即可。(两种类型的最长限定分解的n不等时,其余所有n相等时的限定性分解的U均不相同,可自行推导)

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
隐藏
变装