これらの関数シグネチャを見てください。
class Number {
public:
Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
Prefix はパラメーターを取りませんが、postfix は受け取ります。なんで?さまざまな戻り値の型でそれらを認識できると思いました。
これらの関数シグネチャを見てください。
class Number {
public:
Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
Prefix はパラメーターを取りませんが、postfix は受け取ります。なんで?さまざまな戻り値の型でそれらを認識できると思いました。
接頭辞と接尾辞++
は異なる演算子です。標準的なFoo operator symbol(Foo &)
スタイル宣言では、この 2 つを明確に区別する方法はありませんでした。Foo symbol operator(Foo &)
言語設計者は、他のすべての演算子とは異なり、おそらく解析が少し面倒になるような新しい構文を考え出すのではなく、他の解決策を求めていました。
彼らが選んだ解決策は、やや奇妙でした。彼らは、他のすべての「後置」演算子 (つまり、オペランドの 1 つの後に発生する演算子) は、実際には 2 つの引数を取る中置演算子であることに注意しました。たとえば、普通の+
、/
または>
. これに基づいて、言語設計者は、ランダムな仮引数を持つことが prefix と postfix を区別する良い方法になると判断しました++
。
私見ですが、これは C++ の進化に伴って下された奇妙な決定の 1 つです。しかし、そこにあります。
また、2 つの理由から、戻り値の型に基づいてそれらを区別することはできません。
1 つ目は、C++ の関数は戻り値の型でオーバーロードできないことです。名前とパラメーターの型リストが同じで、戻り値が異なる 2 つの関数を使用することはできません。
2 つ目は、メソッドが、 prefix および postfix のすべての可能な実装を処理するのに十分な堅牢性または柔軟性を備えていないこと++
です。
たとえば、++
それを呼び出した唯一の理由が、適用先の変数の値に関係のない副作用を呼び出すことである場合、参照型を返す接尾辞が必要になる場合があります。私の意見では、それは非常に悪い実装になりますが、C++ は、どのような愚かなコードを書きたいかを判断することではなく、状況に適していると思われるコードを書くことを可能にするものです。++
また、接頭辞と接尾辞に特定のスタイルの戻り型を使用することを強制することは++
、その精神に反することになります。
operator++ には任意の戻り値の型を自由に指定できるため、接尾辞と接頭辞を区別する方法はありません。したがって、コンパイラには何らかの手がかりが必要です。
OTOH、これが構文だけで実行できなかった理由がわかりません。
//prefix
int& ++operator ();
//postfix
int& operator++ ();
結局のところ、宣言での使用法を模倣することは、C および C++ の伝統です。
PS その他のポスター: これは、戻り値の型によるオーバーロードとは関係ありません。postfix と prefix ++/-- は 2 つの異なる名前です。x++
またはでオーバーロードを解決する必要はありません++x
。これは、どちらの名前が意味するかが完全に明確であるためです。
Bjarne の口から直接:
これはかわいすぎて微妙すぎるかもしれませんが、機能し、新しい構文を必要とせず、狂気への論理があります。他の単項演算子は接頭辞であり、メンバー関数として定義されている場合は引数を取りません。「奇数」および未使用の仮
int
引数は、奇数の後置演算子を示すために使用されます。つまり、後置の場合、++
は最初の (実) オペランドと 2 番目の (ダミー) 引数の間にあるため、後置になります。これらの説明が必要なのは、メカニズムが独特であり、それゆえに少しいぼであるためです. 選択肢があれば、
prefix
andpostfix
キーワードを導入することもできたでしょうが、その時点では実現可能ではないように思われました。ただし、唯一の本当に重要なポイントは、メカニズムが機能し、それを本当に必要としている少数のプログラマーが理解して使用できることです。
ちなみに、私の意見では、prefix だけ++
はプログラマーがオーバーロードできるようにすべきで、postfix++
はコンパイラーによって自動的に生成されるべきです。誰かが私に同意しますか?
operator++()
戻り値の型だけで関数をオーバーロードすることは許可されていないため、見た目が同じ 2 つの演算子を区別するには、ダミー パラメーターが必要です。
私がドラザーを持っていた場合、ポストインクリメントと多くのシーケンスポイント演算子は2つまたは3つの部分に分割されます。ポストインクリメントの場合、「a =(b ++ + c ++);」のようなステートメント 「a=postinc1(b)+ postinc1(c); postinc2(b); postinc2(c);」として効果的に翻訳されます。ポストインクリメントの2番目の部分はvoid関数になります。実際の実装では、postinc2()呼び出しは、他の結果が評価スタックにあるときに発生する可能性があります。コンパイラが実装するのはそれほど難しいことではありません。
「&&」または「||」の場合、演算子の最初の部分は左側のオペランドを操作するだけです。ゼロ以外(&&の場合)またはゼロ以外(||の場合)を返した場合、2番目の部分は両方のオペランドで動作します。
「?」/「:」の場合、演算子の最初の部分は最初のオペランドだけで動作します。ゼロ以外を返した場合、2番目の部分は1番目と2番目のパラメーターで動作します。それ以外の場合、3番目の部分は1番目と3番目のパラメーターで動作します。
そのようなことをする言語はありますか?C ++では、シーケンス動作を破る方法で演算子を再定義できますが、それを維持する方法で演算子を再定義することはできません。
コンパイラは int 引数を使用して、前置インクリメント演算子と後置インクリメント演算子を区別します。暗黙的な呼び出しの場合、デフォルト値はゼロであるため、実際にはオーバーロードされた演算子の機能に大きな違いはありません...