web-dev-qa-db-ja.com

C ++では複数のプリインクリメントが許可されているが、Cでは許可されないのはなぜですか?

なぜですか

int main()
{
    int i = 0;
    ++++i;
}

有効なC++ですが無効なC?

40
code_dragon

CとC++は、接頭辞++の結果について異なることを述べています。 C++の場合:

[expr.pre.incr]

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

したがって、結果は基本的にインクリメントされるオブジェクトであり、左辺値なので、++を結果に再度適用できます。 Cではただし:

6.5.3単項演算子

プレフィックスのインクリメントまたはデクリメント演算子のオペランドは、アトミック、修飾、または非修飾の実数型またはポインター型であり、変更可能な左辺値である必要があります

接頭辞++演算子のオペランドの値が増分されます。 結果は、増分後のオペランドの新しい値です。

結果は左辺値ではありません。これは、増分の純粋な値です。したがって、++を含め、左辺値を必要とする演算子を適用することはできません。

C++とCが互いにスーパーセットまたはサブセットであると言われた場合は、そうではないことを知っておいてください。その主張を誤りにする多くの違いがあります。

Cでは、それは常にそうでした。おそらく、プリインクリメントされた++は、++コンセプトが開発された1970年代のものを含む、多くのCPU上の単一のマシンコード命令に最適化できるためです。

C++では、考慮すべき演算子のオーバーロードとの対称性があります。 Cに一致させるには、ユーザー定義タイプと組み込みタイプの異なる動作(においになる)がない限り、正規のプリインクリメント++const &を返す必要があります。 const &への復帰を制限することは、工夫です。そのため、組み込み型のCPU最適化を利用するためにコンパイラの複雑さが増す代わりに、++の戻りはCルールから緩和されます。

14
Bathsheba

C++で問題ない理由を理解していると思いますので、詳しくは説明しません。

それが価値があるものは何でも、ここに私のテスト結果があります:

t.c:6:2: error: lvalue required as increment operand
  ++ ++c;
  ^

CppReference について:

非lvalueオブジェクト式

右辺値として通称、非左辺値のオブジェクト式は、オブジェクトを指定しないオブジェクトタイプの式であり、オブジェクトIDまたは格納場所を持たない値です。左辺値以外のオブジェクト式のアドレスは取得できません。

次の式は、非左辺値オブジェクト式です。

  • すべての演算子左辺値を返すように指定されていません

    • インクリメント演算子とデクリメント演算子(注:プリフォームはC++では左辺値です)

N1570のセクション6.5.3.1:

接頭辞++演算子のオペランドの値が増分されます。 結果は、増分後のオペランドの新しいvalueです。

したがって、Cでは、前置インクリメントおよび前置デクリメント演算子の結果はlvalueである必要はありませんであり、したがって、再度インクリメントできません。実際、そのようなWordは「右辺値である必要がある」と理解できます。

4
iBug

他の答えは、標準が要求するものに分岐する方法を説明しています。この回答は、違いの領域におけるやる気を起こさせる例を提供します。

C++では、int& foo(int&);のような関数を使用できますが、Cには類似物がありません。C++にfoo(foo(x));のオプションがあると便利です(面倒ではありません)。

基本的な型の操作がどこかで定義されていると想像してみてください。 int& operator++(int&);++++x自体は動機付けの例ではありませんが、上記のfooのパターンに適合します。

2
Caleth