为什么以及何时三元运算符返回左值?

问题描述 投票:39回答:3

很长一段时间以来,我认为三元运算符总是返回一个右值。但令我惊讶的是,事实并非如此。在下面的代码中,我没有看到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 ;
}
c++ conditional-operator rvalue lvalue
3个回答
35
投票

ij都是glvalues(详见this value category reference)。

然后,如果你读this conditional operator reference,我们来到这一点:

4)如果E2和E3是相同类型和相同值类别的glvalues,则结果具有相同的类型和值类别

所以(i < 3) ? i : j的结果是一个glvalue,可以分配给它。

但是做这样的事情真的不是我推荐的。


19
投票

[expr.cond]详细说明了这方面的规则。对于几种类型和值类别的组合,有许多分支。但最终,表达式是默认情况下的prvalue。第5段涵盖了您的示例中的案例:

如果第二个和第三个操作数是相同值类别的glvalues并且具有相同的类型,则结果是该类型和值类别,如果第二个或第三个操作数是位字段,则它是位字段,或者如果两者都是位字段。

作为变量名称的ij都是int类型的左值表达式。所以条件运算符产生一个int左值。


2
投票

如果第二个和第三个操作数的类型是左值,则三元条件运算符将产生左值。

您可以使用函数模板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的操作数应该是不会发生衰减的(例如衰减到指针的数组)。

© www.soinside.com 2019 - 2024. All rights reserved.