web-dev-qa-db-ja.com

(++ i)++が有効なのに「++ i ++」が無効なのはなぜですか?

次のコードを考えてみましょう:

_int main() {
    int i = 2;
    int b = ++i++;
    return 3;
}
_

次のエラーでコンパイルされます。

_<source>: In function 'int main()':

<source>:3:16: error: lvalue required as increment operand

    3 |     int b = ++i++;

      |                ^~
_

これは私には公平に聞こえます。 Postfixの増分は、prefixの増分よりも優先度が高いため、コードはint b = ++(i++);として解析され、iは右辺値です。したがってエラー。

デフォルトの優先順位を上書きするために、括弧を付けたこのバリアントについて考えてみましょう。

_int main() {
    int i = 2;
    int b = (++i)++;
    return 3;
}
_

このコードはコンパイルして3を返します。それ自体では、これは公平に聞こえますが、最初のコードと矛盾しているようです。

質問:lvalueがないのに_(++i)_がiである理由

ありがとう!

UPDATE:上記のエラーメッセージはgcc(x86-64 9.2)からのものです。これが正確なレンダリングです: gccのエラー

Clang x86-64 9.0.0にはまったく異なるメッセージがあります: clangでのエラー

_<source>:3:13: error: expression is not assignable

    int b = ++i++;

            ^ ~~~
_

GCCを使用すると、問題がpostfix演算子にあるという印象を受け、_iがOKでないのに_++i_がOKである理由をさまようことができるので、私の質問です。 Clangを使用すると、問題が前置演算子にあることがより明確になります。

14
Bktero

iと_++i_はどちらも左辺値ですが、_i++_は右辺値です。

++(i++)は、接頭辞_++_が右辺値である_i++_に適用されているため、有効にできません。ただし、_(++i)++_は左辺値であるため、_++i_は問題ありません。

Cでは状況が異なることに注意してください。 _i++_および_++i_はどちらも右辺値です。 (これは、CとC++が同じルールを持っていると人々が考えるのをやめるべき理由の例です。人々はこれらの仮定を質問に挿入しますが、それは反駁されなければなりません。)

23
Brian

この宣言

int b = ++i++;

に相当

int b = ++( i++ );

後置インクリメント演算子は、インクリメント前のオペランドの値を返します。

C++ 17標準から(8.2.6インクリメントとデクリメント)

1 Postfix ++式の値は、そのオペランドの値です...結果はprvalueです

単項インクリメント演算子は、インクリメント後にlvalueを返します。この宣言は

int b = (++i)++;

有効です。あなたは例えば書くことができます

int b = (++++++++i)++;

C++ 17標準から(8.3.2インクリメントとデクリメント)

1接頭辞++のオペランドは、1を追加することによって変更されます。オペランドは、変更可能な左辺値でなければなりません。オペランドの型は、cv bool以外の算術型、または完全に定義されたオブジェクト型へのポインターでなければなりません。 結果は更新されたオペランドです。これは左辺値です、およびオペランドがビットフィールドの場合はビットフィールドです...

Cでは両方の演算子が左辺値ではなく値を返すことに注意してください。したがって、Cではこの宣言

int b = (++i)++;

無効です。

4

したがって、コードはint b = ++(i ++);として解析されます。そして、私は右辺値です。

いいえ。iは右辺値ではありません。 iは左辺値です。 i++は右辺値(具体的にはprvalue)です。

3
eerorika