在 C++ 中链接用户转化

Chaining user conversions in c++

本文关键字:用户 链接 C++      更新时间:2023-10-16

考虑以下代码段:

#include <iostream>
struct C
{
C() 
{   
std::cout << "C()n";
}   
explicit C(const C&) 
{   
std::cout << "C(const C&)n";
}   
operator int()
{   
std::cout << "int()n";
return 1;
}   
C(int)
{   
std::cout << "C(int)n";
}   
};
int main()
{
C c1; 
std::cout << 'n';
C c2 = c1; 
std::cout << 'n';
C c3(c1);
}

g++clang都给出以下输出:

C()
int()
C(int)
C(const C&)

这是否违反了隐式转换序列最多可以包含一个用户转换的规则?

这只会编译,因为您正在初始化类C,并在第C c2 = c1;行中使用它自己。如果你有一个类D它的行为与C相同并尝试D d; C c = d;,它不会编译,原因如下:因为隐式转换需要两个用户定义的转换。恶魔

当使用同一个类时,它编译的原因是当y类型为A或派生自它时,复制初始化(A x = y;)的行为不同。在这种情况下,选择一个转换构造函数,然后使用参数y调用该构造函数,这可能会导致隐式转换。构造函数调用本身不是隐式转换的一部分。

因此,在您的代码中,转换序列仅包含一个用户定义的转换:Cint,因为构造函数C(int)是单独调用的。

见C++14 8.5/17:

  • 如果初始化是直接初始化,或者如果是复制初始化,其中 cv 不合格 源类型的版本与目标的类是同一类或派生类, 考虑构造函数。枚举适用的构造函数 (13.3.1.3),并且最好的 通过过载分辨率 (13.3) 选择一个。调用如此选择的构造函数来初始化 对象,初始值设定项表达式或表达式列表作为其参数。
  • 否则(即,对于剩余的复制初始化情况),用户定义的转换序列 可以从源类型转换为目标类型或(当转换函数时) 被使用)到其派生类被枚举 [...]

在 http://en.cppreference.com/w/cpp/language/copy_initialization 阅读更多内容。