C++条件运算符的返回类型

本文深入探讨了C++中的条件运算符(三元运算符)的使用规则和类型推导机制,解释了如何根据条件选择不同类型的表达式,并讨论了在实际编程中可能遇到的类型转换问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

稍微总结了一下,还是有很多不明白的地方的。有一些是粘贴自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&才对呀..

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值