稍微总结了一下,还是有很多不明白的地方的。有一些是粘贴自cppreference.com的
条件运算符表达式的形式为
E1 ? E2 : E3
对条件运算符的第一操作数求值并将其按语境转换为 bool。当第一操作数的值计算和所有副作用完成之后,若结果为 true,则求值第二操作数。若结果为 false,则求值第三操作数。
条件表达式 E1 ? E2 : E3 的类型和值类别按照下列规则确定:
1. 若 E2 或 E3 具有 void 类型,则下列之一必须为真,否则程序非良构:
1.1 E2 或 E3(但非两者)为(可带括号的)throw 表达式。条件运算符的结果具有另一表达式的类型和值类别
std::cout << std::is_same<decltype(true ? int() : throw std::logic_error(“”)), int>::value << std::endl; //output: 1
1.2 E2 和 E3 都具有 void 类型(包括两者均为 throw 表达式的情况)。结果为 void 类型的纯右值
std::cout << std::is_same<decltype(true?throw std::logic_error(“”): throw std::logic_error(“”)), void>::value << std::endl;
//output: 1
2.否则,若 E2 与 E3 拥有不同类型且至少有一个是(可有 cv 限定的)类类型,或都是同一值类别的泛左值且具有除了 cv 限定性之外都相同的类型,则尝试组成隐式转换序列,从每个操作数转换到由另一操作数所确定的目标类型,如下文所述。一个名为 X 的 TX 类型的操作数,能以如下方式转换成另一名为 Y 的 TY 类型操作数的目标类型:
2.1 若 Y 为左值,则目标类型为 TY&,且引用必须直接绑定到左值;
struct A{};
struct B : public A{};
struct C{};
A a;
B b;
C zzz;
std::string str = “123”;
const std::string ch = “1234”;
int c = 10;
int d = 10;
long e = 10;
std::cout << std::is_same<decltype(false ? ch : str), const std::string&>::value << std::endl; //output: 1
std::cout << std::is_same<decltype(false ? a : b), A&>::value << std::endl; //output: 1
std::cout << std::is_same<decltype(false ? c : d), int&>::value << std::endl; //output: 1
2.2 若 Y 为亡值,则目标类型为 TY&&,且引用必须直接绑定;
std::cout << std::is_same<decltype(false ? std::move(ch) : std::move(str)), const std::string&&>::value << std::endl; //output: 1
std::cout << std::is_same<decltype(false ? std::move(ch) : str), std::string>::value << std::endl;
//output: 1 why?难道两个都是xvalue才能类型为&&吗
2.3 若 Y 为纯右值,或若两个转换序列都无法组成,且 TX 和 TY 至少有一个是(可为 cv 限定的)类类型,
2.3.1 若 TX 和 TY(忽略 cv 限定性)为相同类类型,且 TY 至少有 TX 的 cv 限定,则目标类型为 TY
2.3.2 否则,若 TY 是 TX 的基类,则目标类型为带有 TX 的 cv 限定符的 TY
2.3.3 否则,目标类型为 Y 在应用左值到右值、数组到指针和函数到指针标准转换后会有的类型。
std::cout << std::is_same<decltype(false ? A() : B()), A>::value << std::endl; //output: 1
2.4 若两个序列(E2 到 E3 的目标类型和 E3 到 E2 的目标类型)均可组成,或只能组成一个但它是有歧义转换序列,则程序非良构。
2.5 若恰能组成一个转换序列(注意它仍然可能非良构,例如由于访问违规),则应用该转换序列,此描述的余下部分(从 (3) 开始)中用转换后的操作数取代原操作数。
2.6 若不能组成任何转换序列,则在此描述的余下部分中保留各操作数不变。
3. 若 E2 与 E3 是同类型和同值类别的泛左值,则结果具有相同的类型和值类别
4. 否则,结果为纯右值
std::cout << std::is_same<decltype(false ? c : e), long>::value << std::endl; //output: 1
std::cout << std::is_same<decltype(false ? 10 : 11), int>::value << std::endl; //output: 1
std::cout << std::is_same<decltype(false ? a : zzz), int&>::value << std::endl; //ERROR! Can’t compile
简单讲就是条件运算符会尝试双向的隐式类型转换。正常来说是只有一个方向可以转。转过去后就是对应的类型。若是两个方向都能转,是不好的设计。若是两个类没有任何关联,则无法通过编译,除非重载?:操作符
疑问:
struct D
{
D(int d) {}
};
D d(1);
std::cout << std::is_same<decltype(false ? d : 1), D>::value << std::endl; //output: 1
根据2.1 1转换为d的类型,d是左值,那decltype(false ? d : 1)应该是D&才对呀..