用户定义转换的第二个标准转换序列
Second standard conversion sequence of user-defined conversion
我对标准转换序列术语有一个误解。我看到了以下引用N3797§8.5.3/5[dcl.init.ref]:
如果初始值设定项表达式
是一个xvalue(但不是位字段)、类prvalue、数组prvalue或函数左值和">cv1T1"是与">cv2T2"或兼容的参考
--具有类类型(即,T2是类类型),其中T1不是与T2相关的引用,并且可以转换为xvalue、classprvalue,或类型为">cv3T3"的函数左值,其中">cv1T1"为与">cv3T3"兼容的参考(见13.3.1.6),
[..]在第二种情况下,如果引用是右值引用,并且是用户定义转换的第二个标准转换序列序列包括一个左值到右值的转换,程序是不正规。
这里的第二个标准转换序列是什么?我认为有一个标准转换序列,包括所有必要的标准转换(用户定义的和隐式的)。
[over.ics.user]:
用户定义的转换包括一个初始标准转换序列,然后是一个用户定义转换(12.3),然后是第二个标准转换序列。[…]
第二个标准转换序列转换用户定义的到序列目标类型的转换。
例如,对于
struct A
{
operator int();
};
void foo(short);
foo(A());
第二标准转换序列将int
prvalue转换为foo
的参数,即short
。第一个标准转换序列将A
对象转换为A
(operator int
的隐式对象参数),这构成了身份转换
对于参考,您引用的规则提供了一个示例:
struct X {
operator B();
operator int&();
} x;
int&& rri2 = X(); // error: lvalue-to-rvalue conversion applied to
// the result of operator int&
这里,operator int&
是通过过载分辨率来选择的。返回值是对int
的左值引用。为了初始化引用,需要进行左值到右值的转换,而这正是引号所阻止的:lvalue不应绑定到右值引用。
标准转换术语的含义包含在C++标准的以下条款中:
4标准转换
[conv]
标准转换是具有内置含义的隐式转换。第4条列举了这类转换的全部内容。标准转换序列是以下顺序的标准转换序列:
--从以下集合进行零或一次转换:左值到右值的转换,数组到指针的转换,以及函数到指针的转换。
--以下集合的零或一转换:积分提升、浮点提升、积分转换、浮点转换、浮点积分转换、指针转换、指针到成员转换和布尔转换。
--零个或一个资格转换。
[注意:标准转换序列可以为空,也就是说,它可以不包含转换。-->em>结束注释]
如果需要,将标准转换序列应用于表达式,以将其转换为必需的目的地类型。
换句话说,标准转换是编译器在将一种类型转换为另一种类型时可以应用的一组内置规则。这些内置转换包括:
- 没有转换
- 左值到右值的转换
- 数组到指针的转换
- 函数到指针的转换
- 资格转换
- 整体促销
- 浮点促销
- 积分转换
- 浮点转换
- 浮点积分转换
- 指针转换
- 指向成员转换的指针
- 布尔转换
标准转换序列可以在用户定义的转换序列-期间出现两次,在自定义转换之前和/或之后:
§13.3.3.1.2用户定义的转换序列
[over.ics.user]
用户定义的转换序列由初始标准转换序列、用户定义的转化(12.3)和第二个标准转换序列组成。如果用户定义的转换是由构造函数指定的(12.3.1),则初始标准转换序列会将源类型转换为构造函数参数所需的类型。如果用户定义的转换是由转换函数(12.3.2)指定的,则初始标准转换序列会将源类型转换为转换函数的隐式对象参数。
第二个标准转换序列将用户定义转换的结果转换为序列的目标类型。由于隐式转换序列是初始化,当为用户定义转换序列选择最佳用户定义转换时,用户定义转换初始化的特殊规则适用(见13.3.3和13.3.3.1)
话虽如此,对于以下转换:
A a;
B b = a;
编译器将在
B
中搜索转换构造函数,该构造函数可以通过一些初始标准转换序列获取A
的实例(源类型),然后应用另一个标准转换-第二标准转换-用于将用户定义转换的结果类型转换为目标类型;或:
编译器将在
A
中搜索在隐式上下文的某个初始标准转换序列之后可调用的转换函数,然后该函数可以将A
的实例转换为可通过另一个标准转换(第二个标准转换)转换为目标类型B
的某种类型。
作为一个具体的例子,让我们考虑以下转换:
struct A
{
operator int() const;
};
A a;
bool b = a;
编译器考虑以下用户定义的转换序列:
初始标准转换:
A*
到const A*
的资格转换调用const
-合格operator int() const
。自定义转换:通过自定义转换函数将
A
转换为int
。第二个标准转换:
int
到bool
的布尔转换。
您询问的案例可以分为以下几种:
struct A
{
operator int&();
};
int&& b = A();
- 源类型为
A
- 目标类型为
int&&
- 用户定义的转换序列是
A
到int&&
的转换 - 初始标准转换序列是根本没有转换
- 用户定义的转换是
A
到int&
的转换 - 第二个标准转换序列(将用户定义转换的结果转换为目标类型)是整体用户定义转换序列的一部分,此处为
int&
到int&&
的标准转换-一个Lvalue到rvalue的转换。由于int&
和int&&
是引用兼容的类型,因此考虑了该转换。根据以下陈述§8.5.3[dcl.init.ref]/p5:
[…]如果引用是右值引用,并且用户定义的转换序列的第二个标准转换序列包括左值到右值的转换,则程序格式错误。
该转换不适用于整个用户定义的转换序列。
- 如何正确将字符串转换为标准::时间::system_clock::time_point?
- 如何在 C++11 中将标准::字符串转换为标准::u32字符串?
- 从标准::字符串到标准::矢量<bool>的快速转换
- 将手写循环转换为标准库调用
- C++ - 转换标准::浮点数组的字符串
- 如何将 tbb concurrent_hash_map转换为常规标准::地图?
- 从常量字符*、字符*参数到标准::字符串的直接转换接口
- 热将标准::__cxx11::字符串转换为标准::字符串
- C++17 编解码器在将标准::字符串转换为标准::字符串时抛出"bad conversion"
- 如何将 C 数组转换为标准::initializer_list?
- 从双秒到标准::时间:steady_clock::d的简短转换?
- 标准是否阻止在可变参数模板中使用足够小的文本值缩小文本转换范围
- 常量转发引用给出错误 C2440:"正在初始化":无法从"常量标准::字符串"转换为"常量标准::字符串 &&"
- 将 boost:::chrono::steady_clock::time_point 转换为标准::时间::steady
- 如何将标准::string_view转换为双倍?
- 如何在不复制数据的情况下将 cv::Mat 转换为 2d 标准::矢量
- 快速转换标准::时间::time_point 到/从标准::字符串
- 转换标准::basic_string<wchar_t>和标准::basic_string<uint16_t>
- 转换标准::字符串到字符
- 当我使用 win32 发送消息发送和转换标准字符串时,我得到奇怪的字符