如何确定三元运算符的返回类型?
How is the return type of a ternary operator determined?
我正在解决一个关于主教在棋盘上移动的问题。在我的代码的某一点,我有以下语句:
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
这将生成以下错误:
error: invalid operands of types 'int' and '<unresolved overloaded function type>' to binary 'operator<<'
但是,我通过在代码中包含附加变量来立即修复此错误:
int steps = (abs(c2-c1) == abs(r2-r1)) ? 1 : 2;
std::cout << steps << std::endl;
三元运算符如何工作,其返回类型如何确定(编译器称之为<unresolved overloaded function type>
(?
这与如何推导返回类型无关,而与运算符优先级有关。 当你有
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
它不是
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
因为?:
的优先级低于<<
. 这意味着你实际拥有的是
(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl);
这就是为什么你会得到一个关于<unresolved overloaded function type>
的错误。 只需使用括号,例如
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
你会没事的。
你必须在三元运算两边加上括号:
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
如果不是,<<
运算符将转到2
并给出错误,因为它没有这样的重载函数。
这是因为按位左移运算符(<<
(的优先级高于三元运算符。您可以在C++参考的此页面中查看运算符的完整列表及其优先级。
由于运算符优先级,该行被视为:
(std::cout << (abs(c2-c1) == abs(r2-r1))) ? 1 : (2 << std::endl);
将其更改为
std::cout << ((abs(c2-c1) == abs(r2-r1)) ? 1 : 2) << std::endl;
// ^----------------------------------^
// Surrounding parentheses
当解析顺序可视化时,很容易看到错误:
std::cout << (abs(c2-c1) == abs(r2-r1)) ? 1 : 2 << std::endl;
_______/ <--- #1
________________________/ V ~~~~error~~~/ <--- #2
_____________________________________________/ <--- #3
__________________________________________________________/ <--- #4
___________________________________________________________/ <--- #5
你提出的问题的字面答案是C++语言标准 [expr.cond] 部分中的算法。
基本规则"确定是否可以从第二个操作数到为第三个操作数确定的目标类型形成隐式转换序列,反之亦然。 如果没有一个可能的转换,或者有多个转换,则为语法错误,但有几种特殊情况(此处不适用(:
- 如果两者都是算术或
enum
类型,您将获得相同的p ? a : b
隐式转换,以确定表达式的类型,例如a + b
或a * b
。 - 其中一个目标可能是
throw
表达式,并被视为具有另一个目标的类型。 - 如果其中一个目标是位域,则条件表达式的类型也是如此
- 具有不同限定符(如
const
和volatile
(的指针的限定符是统一的。
如果目标是相同类型的 gl值,则结果为 glvalue,否则为 prvalue。
如有疑问,您始终可以显式强制转换一个或两个操作数,以便它们具有相同的类型。
正如公认的答案所解释的那样,您在此处的实际问题是运算符优先级。 也就是说,编译器将第三个操作数解析为2 << std::endl
,而不是 2。
根据 cpp 偏好:
解析表达式时,与在其下方优先级较低的行上列出的任何运算符相比,在上表的某行中列出并具有优先级的运算符将更紧密地绑定到其参数(就像用括号一样(。例如,表达式
std::cout << a & b
和*p++
被解析为(std::cout << a) & b
和*(p++)
,而不是std::cout << (a & b)
或(*p)++
。具有相同优先级的运算符在其关联性方向上受其参数的约束。例如,表达式
a = b = c
被解析为a = (b = c)
,而不是因为赋值的从右到左结合性而被解析为(a = b) = c
,但a + b - c
被解析为(a + b) - c
而不是a + (b - c)
因为加法和减法的从左到右结合性。关联性规范对于一元运算符是多余的,并且仅出于完整性而显示:一元前缀运算符始终从右到左关联(
delete ++*p
delete (++(*p)))
,一元后缀运算符始终从左到右关联(a[1][2]++
为((a[1])[2])++
(。请注意,关联性对于成员访问运算符是有意义的,即使它们与一元后缀运算符分组:a.b++
(a.b)++
解析而不是a.(b++)
。运算符优先级不受运算符重载的影响。例如,
std::cout << a ? b : c;
解析为(std::cout << a) ? b : c;
因为算术左移的优先级高于条件运算符。
- 为什么重载运算符可以返回其返回类型以外的其他内容?
- 错误:为"运算符 std::string {aka std::__cxx11::basic_string}"指定的返回类型<char>
- 运算符和返回类型是什么意思?
- 为什么类的赋值运算符的返回类型通常是非常量(而不是常量)引用?
- 重载运算符返回什么类型的值(对于用户定义的类型):右值还是左值?
- 如何确定三元运算符的返回类型?
- 范围分辨率运算符在类型:: var的情况下返回什么
- 如何使模板化运算符推断出正确的返回类型
- 重载常量和非常量转换运算符返回数组类型时出现 MSVC 错误 C2593
- 根据运算符推断模板返回类型:结果
- 重写运算符的返回类型=
- 错误:"运算符="不匹配 |结构返回类型
- 我无法让这个虚拟模板化函子运算符返回正确的类型
- 使用 std::function 时选择自动返回类型而不是构造函数的调用运算符
- 条件运算符的返回类型和两阶段查找
- 如何使用内置返回类型重载运算符?
- 分配运算符的返回类型
- C++关于引用运算符返回类型的基本概念
- C++移动分配运算符返回类型
- 算术运算符返回类型