'?:'の戻り型(3項条件演算子)


208

なぜ最初のものが参照を返すのですか?

int x = 1;
int y = 2;
(x > y ? x : y) = 100;

2番目はありませんか?

int x = 1;
long y = 2;
(x > y ? x : y) = 100;

実際、2番目はまったくコンパイルされませんでした-「割り当ての左辺値ではありません」。


1
うーん、それはパンを焼くための特別なケースを見つけるようなもので、これまで一度も来ませんでした
Ulterior


式にタイプを割り当てると、少なくとも1つの項がキャストされることになるため、この項はl値ではなくなります。
Yves Daoust、2016年

回答:


173

式には戻り値の型はなく、型と、最新のC ++標準で知られているように、値のカテゴリがあります。

条件式は左辺値または右辺値にすることができます。これがその価値カテゴリーです。(これは、C++11左辺値、x値、およびprvalueがあるため、多少単純化されています。)

非常に広く単純な用語では、左辺値はメモリ内のオブジェクトを指し、右辺値はメモリ内のオブジェクトに必ずしも関連付けられていない場合がある値にすぎません。

割り当て式はオブジェクトに値を割り当てるため、割り当てられるものは左辺値でなければなりません。

条件式(?:)を左辺値(ここでも、広義で単純な用語)にするには、2番目と3番目のオペランドが同じ型の左辺値でなければなりません。これは、条件式のタイプと値のカテゴリーがコンパイル時に決定され、条件が真かどうかに関係なく適切でなければならないためです。オペランドの一方が他方に合わせて異なる型に変換されなければならない場合、条件式であることができない左辺値ではないであろう、この変換の結果として左辺値

ISO / IEC 14882:2011リファレンス:

3.10 [basic.lval]左辺値と右辺値(値カテゴリについて)

5.15 [expr.cond]条件演算子(条件式が持つ型と値のカテゴリの規則)

5.17 [expr.ass]代入演算子と複合代入演算子(代入のlhsは変更可能な左辺値でなければならないという要件)


3
:(私はあなたの答えの前にそれらを聞いたことがなかったので)はxValueとprvalue上に読み込むときに、私は、この便利なSOのポストに出くわしたstackoverflow.com/questions/3601602/...
ふわふわ

an rvalue is just a value that may not necessarily be *attached* to an object in memory.これをもっと簡単な言葉で説明できますか?。また、どういう意味type and value *category*ですか?ありがとう
Mr.Anubis

@SoulReaper:prvalue, xvalue, glvalue値のカテゴリです。
Xeo

@Xeo私は助けに感謝しますが、右辺値によって彼が何を意味しているの、メモリ内のオブジェクトに必ずしも関連付けられていない可能性がある値を教えてください?例では?
Mr.Anubis、

@SoulReaper:私は彼がのようなものの話だと思うtruethisenumの値。これらはprvalues( "pure" rvalues)ですが、メモリには存在しません。
Xeo

57

三項?:式の型は、2番目と3番目の引数の共通型です。両方のタイプが同じ場合、参照が返されます。それらが相互に変換可能である場合、一方が選択され、もう一方が変換されます(この場合は昇格されます)。一時的な(変換/プロモートされた変数)への左辺値参照を返すことはできないため、その型は値型です。


ただし、yはxよりも大きいため、この特定のケースでは昇格の必要はなく、yへの参照を返すことができます。うーん...しかし、私は同意する、それは奇妙だろう。
Yola、2011

1
@ Mr.TAMER:私はむしろ標準を掘り下げたいです。:<
Xeo

3
@ヨラ:型はC ++のコンパイル時の概念であるため、式の実際の戻りは重要ではありません。
Xeo

1
参照は返されず、左辺値が返されます。
須磨

1
@Xeo:C ++の用語ではありませんが、;)
セバスチャンマッハ

19

の型と一致するように暗黙的にの型を昇格させる必要があるため(およびの両側が同じ型ではないため)、一時変数を作成する必要があるため、左辺値を返すことはできません。xy:


標準は何と言っていますか?(n1905

式5.17代入演算子と複合代入演算子

5.17 / 3

2番目と3番目のオペランドの型が異なり、どちらかが(おそらくcv修飾された)クラス型である場合、それらの各オペランドをもう一方の型に変換しようとします。タイプT1のオペランド式E1がタイプT2のオペランド式E2と一致するように変換できるかどうかを判別するプロセスは、次のように定義されます。

— E2が左辺値の場合:E1を暗黙的に変換でき(第4節)、「T2への参照」型に変換できる場合、変換で参照が直接バインドする必要があるという制約に従って、E1をE2に一致するように変換できます(8.5.3 )からE1へ。

— E2が右辺値の場合、または上記の変換を実行できない場合:

— E1とE2にクラスタイプがあり、基になるクラスタイプが同じであるか、一方が他方の基本クラスである場合:T2のクラスが同じタイプの基本クラスまたは、T1のクラス、およびT2のcv-qualificationは、T1のcv-qualificationと同じ、またはそれよりも大きいcv-qualificationです。変換が適用されると、E1は、元のソースクラスオブジェクト(またはその適切なサブオブジェクト)を引き続き参照するT2型の右辺値に変更されます。[ 注:つまり、コピーは作成されません。—エンドノート ]タイプT2の一時ファイルをE1からコピー初期化し、その一時ファイルを変換後のオペランドとして使用する。

それ以外の場合(つまり、 E1またはE2に非クラスタイプがある場合、または両方にクラスタイプがあるが、基礎となるクラスが同じでも、一方が他方の基本クラスでもない場合):E1を変換できる場合、E1をE2に一致するように変換できます。 E2が右辺値に変換された場合に式E2が持つ型(またはE2が右辺値の場合はそれが持つ型)に暗黙的に変換されます。

このプロセスを使用して、2番目のオペランドを3番目のオペランドと一致するように変換できるかどうか、および3番目のオペランドを2番目のオペランドと一致するように変換できるかどうかを決定します。両方を変換できる場合、または1つは変換できるが、変換があいまいな場合、プログラムの形式が正しくありません。どちらも変換できない場合、オペランドは変更されず、以下で説明するようにさらにチェックが行われます。正確に1つの変換が可能な場合、その変換は選択されたオペランドに適用され、このセクションの残りの部分では、変換されたオペランドが元のオペランドの代わりに使用されます。


5.17 / 4

2番目と3番目のオペランドが左辺値で同じ型の場合、結果はその型で左辺値であり、2番目または3番目のオペランドがビットフィールドの場合、または両方がビットフィールドの場合はビットフィールドです。田畑。


5.17 / 5

それ以外の場合、結果は右辺値です。2番目と3番目のオペランドが同じ型ではなく、どちらか(おそらくcv修飾)のクラス型である場合、過負荷解決を使用して、オペランドに適用される変換(存在する場合)を決定します(13.3.1.2、13.6) 。過負荷の解決に失敗した場合、プログラムは不正な形式です。それ以外の場合は、このように決定された変換が適用され、このセクションの残りの部分では、元のオペランドの代わりに変換されたオペランドが使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.