C++ 从三元运算符的一侧移出
我正在编写一些类似以下内容的代码:C++ 从三元运算符的一侧移出,c++,c++11,gcc,clang,C++,C++11,Gcc,Clang,我正在编写一些类似以下内容的代码: std::string foo(bool b, const std::string& fst, std::string&& snd) { return b ? fst : std::move(snd); } 然后叮当一声,将snd复制出去,而gcc将其移出。 我试图尽量减少这个例子,我想到了: #include <iostream> #include <utility> struct printer {
std::string foo(bool b, const std::string& fst, std::string&& snd) {
return b ? fst : std::move(snd);
}
然后叮当一声,将snd
复制出去,而gcc
将其移出。
我试图尽量减少这个例子,我想到了:
#include <iostream>
#include <utility>
struct printer {
printer() { }
printer(const printer&) { std::cout << "copy" << std::endl; }
printer(printer&&) { std::cout << "move" << std::endl; }
printer(const printer&&) { std::cout << "const rvalue ref" << std::endl; }
};
int main() {
const printer fst;
printer snd;
false ? fst : std::move(snd);
}
clang 3.6输出
const rvalue ref
该标准是否同时允许gcc和叮当行为
随机观察结果如下:
gcc和clang都将三元的类型统一为:
const printer
std::move(x)
好的,让我们首先计算一下std::move(snd)的类型。根据§20.2.4:
template constexpr remove\u reference\u t&&move(t&&t)noexcept代码>
返回:static\u cast(t)
根据§5.2.9/1:
表达式static_cast(v)
的结果是将表达式v
转换为类型T
的结果。如果T
是左值引用类型或函数类型的右值引用,则结果为左值如果T
是对对象类型的右值引用,则结果为xvalue;否则,结果是一个pr值。static_cast
操作员不得丢弃常量(5.2.11)
(强调矿山)
好的,std::move(snd)
的返回值是printer&
类型的xvalue。fst
的类型是const printer
类型的左值
如何计算常用类型
现在,标准描述了计算三元条件运算符的结果表达式类型的过程:
如果第二个和第三个操作数具有不同的类型,并且其中一个具有(可能是cv限定的)类类型,或者如果这两个操作数都是相同值类别和相同类型(cv限定除外)的glvalues,则会尝试将这些操作数中的每一个转换为另一个操作数的类型。确定T1类型的操作数表达式E1是否可以转换为与T2类型的操作数表达式E2匹配的过程定义如下:
- 如果E2是左值:如果E1可以隐式转换(第4条)为类型“对T2的左值引用”,则E1可以转换为与E2匹配的值,但必须遵守以下约束,即在转换过程中引用必须直接绑定(8.5.3)到左值
- 如果E2是xvalue:如果E1可以隐式转换为类型“rvalue reference to T2”,则可以将E1转换为与E2匹配的值,但必须遵守引用必须直接绑定的约束
- 如果E2是prvalue,或者上述两种转换都无法完成,并且至少有一个操作数具有(可能是cv限定的)类类型:
- 如果E1和E2具有类类型,且基础类类型相同或其中一个是另一个的基类:如果T2的类与T1的类相同或基类相同,且T2的cv鉴定与T1的cv鉴定相同,或cv鉴定大于,T1的简历资格。如果应用了转换,则通过从E1复制初始化T2类型的临时值并将该临时值用作转换后的操作数,将E1更改为T2类型的prvalue
- 否则(如果E1或E2具有非类类型,或者如果它们都具有类类型,但基础类不相同,也不是另一个的基类):如果E1可以隐式转换为E2在应用左值后将具有的类型,则可以将E1转换为与E2匹配的类型-
右值(4.1)、数组到指针(4.2)和函数到指针(4.3)的标准转换
使用此过程,确定是否可以将第二个操作数转换为与第三个操作数匹配,,以及是否可以将第三个操作数转换为与第二个操作数匹配。如果两者都可以转换,或者其中一个可以转换但转换不明确,则程序的格式不正确。如果两者都不能转换,则操作数保持不变,并按如下所述执行进一步检查。如果只能进行一次转换,则该转换将应用于选定的操作数,并在本节剩余部分使用转换后的操作数代替原始操作数
(再次强调我的)
在这方面
因此,我们有两种情况:
E1是fst,E2是std::move(snd)
常量打印机
)无法隐式转换为打印机&
,因为它将丢失常量。所以这种转换是不可能的
在第二种情况下,我们有:
如果E2是左值:如果E1可以隐式转换(第4条)为类型“对T2的左值引用”,则E1可以转换为与E2匹配的值,但必须遵守以下约束,即在转换过程中引用必须直接绑定(8.5.3)到左值
适用,但E1(std::move(snd)
类型的printer&
)可以隐式转换为const printer&
,但不直接绑定到左值;所以这个也不适用
目前,我们正处于:
如果E2是prvalue,或者上述两种转换都无法完成,并且至少有一个操作数具有(可能是cv限定的)类类型:
节
我们必须从中考虑:
如果E1和E2具有类类型,并且基础类类型相同,或者其中一个是另一个的基类:如果T2的类与cl的类型相同,或者是cl的基类,则可以将E1转换为与E2匹配
const printer