很长一段时间以来,我认为三元运算符总是返回一个右值。但令我惊讶的是,事实并非如此。在下面的代码中,我没有看到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 ;
}
i
和j
都是glvalues(详见this value category reference)。
然后,如果你读this conditional operator reference,我们来到这一点:
4)如果E2和E3是相同类型和相同值类别的glvalues,则结果具有相同的类型和值类别
所以(i < 3) ? i : j
的结果是一个glvalue,可以分配给它。
但是做这样的事情真的不是我推荐的。
[expr.cond]详细说明了这方面的规则。对于几种类型和值类别的组合,有许多分支。但最终,表达式是默认情况下的prvalue。第5段涵盖了您的示例中的案例:
如果第二个和第三个操作数是相同值类别的glvalues并且具有相同的类型,则结果是该类型和值类别,如果第二个或第三个操作数是位字段,则它是位字段,或者如果两者都是位字段。
作为变量名称的i
和j
都是int
类型的左值表达式。所以条件运算符产生一个int
左值。
如果第二个和第三个操作数的类型是左值,则三元条件运算符将产生左值。
您可以使用函数模板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
的操作数应该是不会发生衰减的(例如衰减到指针的数组)。