为什么以及什么时候三元运算符 return 是左值?
Why and when does the ternary operator return an lvalue?
很长一段时间我都认为三元运算符总是 return 是一个右值。但令我惊讶的是它没有。在下面的代码中,我没有看到 foo
的 return 值与三元运算符的 return 值之间的区别。
#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 ;
}
此规则在 [expr.cond] 中有详细说明。类型和值类别的几种组合有许多分支。但最终,表达式在默认情况下是纯右值。第 5 段涵盖了您示例中的案例:
If the second and third operands are glvalues of the same value
category and have the same type, the result is of that type and value
category and it is a bit-field if the second or the third operand is a
bit-field, or if both are bit-fields.
i
和j
都是变量名,都是int
类型的左值表达式。所以条件运算符产生一个 int
左值。
i
和j
都是glvalues(详见this value category reference)。
然后,如果您阅读 this conditional operator reference,我们就会得出这一点:
4) If E2 and E3 are glvalues of the same type and the same value category, then the result has the same type and value category
所以(i < 3) ? i : j
的结果是一个glvalue,可以赋值给
但是我真的不推荐这样做。
三元条件运算符将产生一个左值,如果它的第二个和第三个操作数的类型是左值。
您可以使用函数模板 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
注意:你传递给isTernaryAssignable
的操作数是这样的,它们不会衰减(例如衰减为指针的数组)。
很长一段时间我都认为三元运算符总是 return 是一个右值。但令我惊讶的是它没有。在下面的代码中,我没有看到 foo
的 return 值与三元运算符的 return 值之间的区别。
#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 ;
}
此规则在 [expr.cond] 中有详细说明。类型和值类别的几种组合有许多分支。但最终,表达式在默认情况下是纯右值。第 5 段涵盖了您示例中的案例:
If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.
i
和j
都是变量名,都是int
类型的左值表达式。所以条件运算符产生一个 int
左值。
i
和j
都是glvalues(详见this value category reference)。
然后,如果您阅读 this conditional operator reference,我们就会得出这一点:
4) If E2 and E3 are glvalues of the same type and the same value category, then the result has the same type and value category
所以(i < 3) ? i : j
的结果是一个glvalue,可以赋值给
但是我真的不推荐这样做。
三元条件运算符将产生一个左值,如果它的第二个和第三个操作数的类型是左值。
您可以使用函数模板 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
注意:你传递给isTernaryAssignable
的操作数是这样的,它们不会衰减(例如衰减为指针的数组)。