22

三項演算子 ' ?: ' をオーバーロードできないのはなぜですか?

私は if ステートメントを統合するために三項演算子をよく使用しますが、言語設計者がこの演算子のオーバーロードを禁止した理由に興味があります。C++ 演算子のオーバーロードで理由についての説明を探しましたが、これが不可能な理由を説明する説明は見つかりませんでした。脚注が提供する唯一の情報は、オーバーロードできないということです。

私の最初の推測では、演算子をオーバーロードすると、ほとんどの場合、上記のリンクに示されている原則の 1 つまたは 2 つに違反することになります。オーバーロードの意味が明白または明確になることはめったにないか、元の既知のセマンティクスから逸脱します。

したがって、私の質問は、それができないことを知っているので、どのようにではなく、なぜこれができないのかということです。

4

5 に答える 5

23

三項演算子をオーバーライドできる場合は、次のように記述する必要があります。

xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );

オーバーライドを呼び出すには、コンパイラは と の両方の値を計算する必要がtrueValありfalseValます。これは、組み込みの三項演算子がどのように機能するかではありません。これらの値の 1 つだけを計算するため、次のように記述できます。

return p == NULL ? 23 : p->value;

NULL ポインタによる間接指定について心配する必要はありません。

于 2013-07-30T17:26:38.190 に答える
17

当時の主な理由は、その演算子のためだけに新しい構文を発明する努力をする価値がないように思えたからだと思います。token がない?:ため、そのためだけに特別な文法規則をいくつか作成する必要があります。(現在の文法規則のoperator後には、単一のトークンである演算子が続きます。)

演算子のオーバーロードをより合理的に使用することを (経験から) 学んだように、他の応答が指摘した理由から、&&andのいずれかのオーバーロードを実際に許可すべきではないことが明らかになりました。||オーバーロードされたバージョンには、ユーザーが期待するシーケンス ポイントがないためです)。そのため、それをサポートする動機は当初よりもさらに低くなります。

于 2013-07-30T17:34:59.703 に答える
6

三項演算子の原則の 1 つは、true / false 式が条件式の真偽に基づいてのみ評価されることです。

cond ? expr1 : expr2

この例expr1では、condは true の場合にのみ評価され、は false のexpr2場合にのみ評価されます。condそれを念頭に置いて、三項オーバーロードのシグネチャがどのように見えるかを見てみましょう (簡単にするために、ここではテンプレートの代わりに固定型を使用しています)。

Result operator?(const Result& left, const Result& right) { 
  ...
}

この署名は、私が説明した正確なセマンティクスに違反しているため、正当ではありません。このメソッドを呼び出すために、言語は両方を評価する必要がexpr1あるexpr2ため、条件付きで評価されなくなりました。三項をサポートするために、演算子は次のいずれかを行う必要があります

  1. 必要に応じて値を生成できるように、各値のラムダを取得します。ただし、ラムダが論理的に存在しないラムダ呼び出しのセマンティクスを考慮する必要があるため、これは必然的に呼び出しコードを複雑にします。
  2. expr1三項演算子は、コンパイラが使用するかどうかを示す値を返す必要があります。expr2

編集

このシナリオで短絡がないことは問題ないと主張する人もいるかもしれません。その理由は、C++ では、演算子のオーバーロードでショート サーキットに違反することが既に許可されているためです||&&

Result operator&&(const Result& left, const Result& right) { 
  ...
}

ただし、C++ の場合でも、この動作は依然として困惑しています。

于 2013-07-30T17:31:20.723 に答える
3

簡潔で正確な答えは、単純に「Bjarne がそう決めたから」です。

どのオペランドをどの順序で評価する必要があるかについての引数は、何が起こるかについて技術的に正確な説明を提供しますが、この特定の演算子をオーバーロードできない理由を説明することはほとんどありません (実際には何もありません)。

operator &&特に、同じ基本的な引数は、やなどの他の演算子にも同様に適用されますoperator||。これらの各演算子の組み込みバージョンでは、左側のオペランドが評価され、それが1for&&または0forを生成する場合にのみ||、右側のオペランドが評価されます。同様に、(組み込みの) コンマ演算子は、左側のオペランドを評価してから、右側のオペランドを評価します。

これらの演算子のいずれかのオーバーロードされたバージョンでは、両方のオペランドが常に評価されます (指定されていない順序で)。そのため、この点ではオーバーロードされた三項演算子と本質的に同じです。それらはすべて、どのオペランドがどの順序で評価されるかについて、同じ保証を失います。

Bjarne がその決定を下した理由については、いくつかの可能性が考えられます。1つは、技術的には演算子ですが、三項演算子は主にフロー制御に専念しているため、それをオーバーロードすることは、他のほとんどの演算子をオーバーロードすることよりも、オーバーロードに似ていることですifwhile

別の可能性としては、構文的に見苦しく、パーサーが のようなものを処理する必要があり、トークンとしてoperator?:定義する必要がある?:などです。これらはすべて、C 文法にかなり深刻な変更を加える必要があります。少なくとも私の見解では、C++ はすでに Cよりもはるかに複雑なパーサーを必要とするため、この議論はかなり弱いように思われます。

おそらく、すべての中で最も強力な議論は、それが多くを達成するようには見えなかったということです. 主にフロー制御に専念しているため、一部のタイプのオペランドに対する動作を変更しても、非常に役立つことはほとんどありません。

于 2013-07-30T17:46:23.290 に答える
1

&&演算子や演算子をオーバーロードしてはならないのと同じ理由で (可能ではありますが) ||、そうすると、これらの演算子のショートサーキットが無効になり (すべてではなく必要な部分のみが評価されます)、深刻な問題が発生する可能性があります。

于 2013-07-30T17:28:06.030 に答える