Почему и когда троичный оператор возвращает lvalue? - PullRequest
0 голосов
/ 14 февраля 2019

Долгое время я думал, что троичный оператор всегда возвращает значение.Но, к моему удивлению, это не так.В следующем коде я не вижу разницы между возвращаемым значением 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 ;
}

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

И i, и j glvalues ​​ (подробности см. в этой категории значений ).

Тогда, если вы прочитаете это условное выражениессылка на оператор мы подходим к этой точке:

4) Если E2 и E3 являются glvalues ​​одного и того же типа и той же категории значения, то результат имеет тот же тип и категорию значения

Таким образом, результатом (i < 3) ? i : j является glvalue, которому можно присвоить.

Однако делать что-то подобное на самом деле я бы не рекомендовал.

0 голосов
/ 14 февраля 2019

Тернарный условный оператор выдаст lvalue, если тип его второго и третьего операндов - lvalue.

Вы можете использовать шаблон функции is_lvalue (ниже), чтобы выяснить, является ли операнд 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

Примечание : Theоперанды, которые вы передаете isTernaryAssignable, должны быть такими, чтобы они не подвергались распаду (например, массив, который распадается на указатель).

0 голосов
/ 14 февраля 2019

Правила этого подробно описаны в [expr.cond] .Существует множество веток для нескольких комбинаций типов и категорий значений.Но в конечном счете, выражение является prvalue в случае по умолчанию.Случай в вашем примере охватывается параграфом 5:

Если второй и третий операнды являются glvalues ​​одной и той же категории значений и имеют один и тот же тип, результат будет иметь этот тип и категорию значений, и этоявляется битовым полем, если второй или третий операнд является битовым полем, или если оба являются битовыми полями.

Оба i и j, являющиеся именами переменных, являются lvalueвыражения типа int.Таким образом, условный оператор выдает int lvalue.

...