三元运算符为啥以及何时返回左值?
Posted
技术标签:
【中文标题】三元运算符为啥以及何时返回左值?【英文标题】:Why and when does the ternary operator return an lvalue?三元运算符为什么以及何时返回左值? 【发布时间】:2019-07-08 08:46:14 【问题描述】:长期以来,我一直认为三元运算符总是返回一个右值。但令我惊讶的是,事实并非如此。在下面的代码中,我看不出foo
的返回值和三元运算符的返回值有什么区别。
#include <iostream>
int g = 20 ;
int foo()
return g ;
int main()
int i= 2,j =10 ;
foo()=10 ; // not Ok
((i < 3) ? i : j) = 7; //Ok
std::cout << i <<","<<j << "," <<g << std::endl ;
【问题讨论】:
附带说明,如果您将int foo()
更改为int &foo()
,那么foo()=10;
也可以使用。
“三元运算符总是返回一个右值。令人惊讶的是它确实” 你的意思是“不”,因为它可以返回左值(当双方都是左值时)。
另见***.com/questions/1082655/…。如那里所述,您始终可以使用*((i<3) ? &i : &j) = 7;
,因此 C++ 规则可以概括为“即使没有*&
,它仍然有效”
在 C 中,条件运算符永远不会产生左值。在 C++ 中,有时会这样。这是人们应该避免提及“C/C++”的一个例子。像这样的各种细微差别可能最终与任何特定问题相关。
【参考方案1】:
此规则在[expr.cond] 中有详细说明。对于类型和值类别的几种组合,有许多分支。但最终,表达式在默认情况下是纯右值。第 5 段涵盖了您示例中的情况:
如果第二个和第三个操作数是相同值的glvalues 类别并具有相同的类型,结果是该类型和值 类别,如果第二个或第三个操作数是一个位域 位域,或者如果两者都是位域。
i
和j
都是变量名,都是int
类型的左值表达式。所以条件运算符产生一个int
左值。
【讨论】:
【参考方案2】:i
和 j
都是 glvalues(有关详细信息,请参阅 this value category reference)。
那么,如果您阅读this conditional operator reference,我们就到了这一点:
4) 如果E2和E3是相同类型和相同值类别的glvalues,则结果具有相同的类型和值类别
所以(i < 3) ? i : j
的结果是一个glvalue,可以赋值给。
但是,我真的不建议这样做。
【讨论】:
@SoulimaneMammar 问题在于常量,而不是值类别。您不能将带有已删除operator=
的对象放在分配的左侧;这并不意味着它不是左值。
@Someprogrammerdude - 你的第一条评论代表了左值概念的起源:可以在赋值左侧的东西。虽然概念已经超越了这一点,但名称仍然存在。
@SoulimaneMammar 数组(例如字符串文字)是棘手的左值。当使用它们的值时,它们会隐式转换为指向第一个元素的指针(这称为衰减),并且衰减的指针不是左值。这就是错误诊断的原因。更一般地说,即使数组不是 const,也不能在语言中分配数组。
@SoulimaneMammar - 哪个编译器? gnu c++ 对"Hello" = "World"
的诊断是error: assignment of read-only location '"Hello"'
,而LLVM 的诊断是error: read-only variable is not assignable
。
主要用例是引用的初始化:int &i = b ? i1 : i2;
【参考方案3】:
三元条件运算符将产生一个左值,如果它的第二个和第三个操作数的类型是左值。
您可以使用函数模板is_lvalue
(如下)来判断一个操作数是否为左值,并在函数模板isTernaryAssignable
中使用它来判断它是否可以被赋值。
一个最小的例子:
#include <iostream>
#include <type_traits>
template <typename T>
constexpr bool is_lvalue(T&&)
return std::is_lvalue_reference<T>;
template <typename T, typename U>
bool isTernaryAssignable(T&& t, U&& u)
return is_lvalue(std::forward<T>(t)) && is_lvalue(std::forward<U>(u));
int main()
int i= 2,j =10 ;
((i < 3) ? i : j) = 7; //Ok
std::cout << std::boolalpha << isTernaryAssignable(i, j); std::cout << '\n';
std::cout << std::boolalpha << isTernaryAssignable(i, 10); std::cout << '\n';
std::cout << std::boolalpha << isTernaryAssignable(2, j); std::cout << '\n';
std::cout << std::boolalpha << isTernaryAssignable(2, 10); std::cout << '\n';
输出:
true
false
false
false
LIVE DEMO
注意:您传递给isTernaryAssignable
的操作数将不会衰减(例如衰减为指针的数组)。
【讨论】:
以上是关于三元运算符为啥以及何时返回左值?的主要内容,如果未能解决你的问题,请参考以下文章