すべての設計プロセスは、相互に互換性のない目標間の妥協をもたらします。残念ながら、&&
C ++でオーバーロードされた演算子の設計プロセスは、混乱を招く最終結果を生み出しました。つまり、必要な機能(&&
その短絡動作)が省略されています。
設計プロセスがどのようにしてこの不幸な場所に到達したかについての詳細は、私にはわかりません。ただし、後の設計プロセスでこの不快な結果がどのように考慮されたかを確認することは重要です。C#では、過負荷の&&
演算子は短絡です。C#の設計者はそれをどのように達成しましたか?
他の回答の1つは「ラムダリフティング」を示唆しています。あれは:
A && B
道徳的に同等のものとして実現することができます:
operator_&& ( A, ()=> B )
ここで、2番目の引数は遅延評価のメカニズムを使用するため、評価されると、式の副作用と値が生成されます。オーバーロードされた演算子の実装は、必要な場合にのみ遅延評価を行います。
これは、C#設計チームが行ったことではありません。(脇:ラムダリフティングはかかわらず、であるそれを行うための時間に来たときに私が何をしたかの式ツリー表現のを??
。。特定の変換操作を必要とする作業を、遅延し実行することが詳細にしかし主要な余談になるとの記述十分を言うために:ラムダリフティング動作しますが、回避したかったほど十分に重いです。)
むしろ、C#ソリューションは問題を2つの別個の問題に分解します。
- 右側のオペランドを評価する必要がありますか?
- 上記の答えが「はい」の場合、2つのオペランドをどのように組み合わせるのでしょうか。
したがって、&&
直接オーバーロードすることを違法にすることで問題は解決します。むしろ、C#では2つの演算子をオーバーロードする必要があり、それぞれがこれら2つの質問の1つに答えます。
class C
{
// Is this thing "false-ish"? If yes, we can skip computing the right
// hand size of an &&
public static bool operator false (C c) { whatever }
// If we didn't skip the RHS, how do we combine them?
public static C operator & (C left, C right) { whatever }
...
(脇に:実際には3つあります。C#では、演算子false
が指定されている場合は演算子true
も指定する必要があります。これは、「これは本当ですか?」という質問に答えます。通常、そのような演算子を1つだけ指定する理由はないため、C#両方が必要です。)
次の形式のステートメントについて考えてみます。
C cresult = cleft && cright;
コンパイラは、この疑似C#を記述したと考えられるように、このためのコードを生成します。
C cresult;
C tempLeft = cleft;
cresult = C.false(tempLeft) ? tempLeft : C.&(tempLeft, cright);
ご覧のとおり、常に左側が評価されます。「偽っぽい」と判断された場合はその結果です。それ以外の場合は、右側が評価され、熱心なユーザー定義演算子&
が呼び出されます。
||
オペレータは、オペレータの呼び出し真と熱心なように、類似の方法で定義される|
演算子。
cresult = C.true(tempLeft) ? tempLeft : C.|(tempLeft , cright);
-すべての4つの演算子を定義することでtrue
、false
、&
および|
- C#は、あなたが言うできるだけでなくcleft && cright
だけでなく、非短絡cleft & cright
し、またif (cleft) if (cright) ...
、とc ? consequence : alternative
してwhile(c)
、そしてそうで。
今、私はすべての設計プロセスが妥協の結果であると述べました。ここで、C#言語の設計者は短絡&&
と||
正しい結果を得ることができましたが、そのためには2つではなく4つの演算子をオーバーロードする必要があり、混乱する人もいます。オペレーターのtrue / false機能は、C#で最もよく理解されていない機能の1つです。C ++ユーザーに馴染みのある賢明でわかりやすい言語を使用するという目標は、短絡させたいという欲求や、ラムダリフティングやその他の形式の遅延評価を実装しないという欲望によって反対されました。私は、それが合理的な妥協の位置だったと思うが、それがあることを認識することが重要であるである妥協の位置。ただ違う C ++の設計者が上陸したときよりも妥協の立場。
そのような演算子の言語設計の主題に興味がある場合は、C#がこれらの演算子をnull許容ブールで定義しない理由についての私のシリーズを読むことを検討してください。
http://ericlippert.com/2012/03/26/null-is-not-false-part-one/
operator&&(const Foo& lhs, const Foo& rhs) : (lhs.bars == 0)