その他の演算子
演算子の名前 | 構文 | オーバーロード可能 | プロトタイプの例 (class T に対して) | |
---|---|---|---|---|
クラス定義の内側 | クラス定義の外側 | |||
関数呼び出し | a(a1, a2)
|
Yes | R T::operator()(Arg1 &a1, Arg2 &a2, ... ...); | N/A |
コンマ | a, b
|
Yes | T2& T::operator,(T2 &b); | T2& operator,(const T &a, T2 &b); |
条件演算子 | a ? b : c
|
No | N/A | N/A |
目次 |
[編集] 説明
関数呼び出し演算子は任意のオブジェクトに対し���関数のセマンティクスを提供します。
条件演算子 (俗に三項演算子とも呼ばれます) は、1つめの式のブーリアン値を調べて、その結果の値によって、2つめまたは3つめの式を評価して返します。
[編集] 組み込みの関数呼び出し演算子
関数呼び出し式は以下の形式を持ちます。
E ( A1, A2, A3,... )
|
|||||||||
ただし
- E は関数を表す式です。
- A1, A2, A3,... は任意の式のリストです。 空でも構いません。 ただし、曖昧さを避けるため、括弧で囲まれていないコンマ演算子を使用することはできません。
関数を表す式は以下のいずれかです。
E
によって表される関数 (またはメンバ) 名はオーバーロード可能であり、どのオーバーロードを呼ぶかを決定するためにオーバーロード解決のルールが使用されます。
E
がメンバ関数を表す場合、それは仮想関数であっても構いません。 その場合、実行時に動的ディスパッチを用いてその関数の最終オーバーライドが呼ばれます。
関数を呼ぶとき、
式 |
(C++17未満) |
式 |
(C++17以上) |
関数のそれぞれの仮引数は、必要であれば暗黙の変換を行った後の、対応する実引数で初期化されます。 対応する実引数がない場合は、対応するデフォルト引数が使用されます。 それもない場合は、プログラムは ill-formed です。 呼び出しがメンバ関数に対して行われる場合、現在のオブジェクトの this ポインタはその関数によって期待される this ポインタに、明示的なキャストによって行われたかのように、変換されます。 それぞれの仮引数の初期化および破棄は呼び出し元の文脈で発生します。 つまり、例えば、仮引数のコンストラクタが例外を投げた場合、関数内で定義されている例外ハンドラは (たとえ関数 try ブロックであっても) 考慮されません。 関数が可変長引数を持つ場合、その省略記号の部分にマッチするすべての引数にデフォルトの引数昇格が適用されます。 仮引数の生存期間が、その関数から戻ったときに終了するか、囲っている完全式の終わりで終了するかは、処理系定義です。
関数呼び出し式の戻り値の型は、その選択された関数の戻り値の型です。 たとえ実際に呼ばれるオーバーライドした関数が異なる型を返す場合でも、静的バインディングを用いて (virtual
キーワードを無視して) 決定されます。 これはオーバーライドした関数が基底の関数によって返される戻り値の型から派生したクラスへのポインタや参照を返すことを許容します。 すなわち、 C++ は共変戻り値型をサポートします。 E
がデストラクタを表す場合、戻り値の型は void です。
クラス型 X のオブジェクトが関数に渡されるまたは関数から返されるとき、 X のコピーコンストラクタ、ムーブコンストラクタ、デストラクタがそれぞれトリビアルであるか削除されているかのいずれかであり、 X が少なくともひとつの削除されていないコピーまたはムーブコンストラクタを持つ場合、処理系は関数の引数または戻り値のオブジェクトを保持するための一時オブジェクトを作成することが許されます。 一時オブジェクトは関数の実引数または戻り値から構築され、その関数の仮引数または返されたオブジェクトは一時オブジェクトをコピーするために削除されていないトリビアルなコンストラクタを使用したかのように初期化されます (たとえそのコンストラクタがアクセス可能でなくても、またはオブジェクトのコピーまたはムーブを行うためにオーバーロード解決によって選択されないであろうとも)。 これにより std::complex や |
(C++17以上) |
関数呼び出し式の値カテゴリは、その関数が関数への左辺値参照または右辺値参照を返す場合は lvalue であり、その関数がオブジェクトへの右辺値参照を返す場合は xvalue であり、そうでなければ prvalue です。 関数呼び出し式がオブジェクト型の prvalue である場合、それは完全型でなければなりません。 ただし decltype の被演算子として (または decltype
の被演算子である組み込みのコンマ演算子式の右の被演算子として) 使用されるときなど、その prvalue が具体化されないとき (C++17以上)は除きます。
関数呼び出し式は値初期化 T()、関数スタイルのキャスト式 T(A1)、および一時オブジェクトの直接初期化 T(A1, A2, A3, ...) (ただし T
は型名) と構文が似ています。
#include <cstdio> struct S { int f1(double d) { return printf("%f \n", d); // variable argument function call } int f2() { return f1(7); // member function call, same as this->f1() // integer argument converted to double } }; void f() { puts("function called"); // function call } int main() { f(); // function call S s; s.f2(); // member function call }
出力:
function called 7.000000
[編集] 組み込みのコンマ演算子
コンマ演算子式は以下の形式を持ちます。
E1 , E2
|
|||||||||
コンマ式 E1, E2 において、式 E1
が評価され、その結果が破棄され (クラス型の場合は囲っている完全式の終わりまで破棄されません)、式 E2
の評価が始まる前にその副作用が完了されます (ユーザ定義の operator,
は評価順序を保証できないことに注意してください) (C++17未満)。
コンマ演算子の結果の型、値、値カテゴリは正確に2つめの被演算子 E2
の型、値、値カテゴリです。 E2
が一時オブジェクト式 (C++17以上)の場合、式の結果はその一時オブジェクト式 (C++17以上)です。 E2
がビットフィールドの場合、結果はビットフィールドです。
関数の引数リスト (f(a, b, c)) や初期化子リスト int a[] = {1,2,3} などの様々なコンマ区切りリスト内のコンマは、コンマ演算子ではありません。 そのような文脈でコンマ演算子を使用する必要がある場合は、括弧で囲む必要があります f(a, (n++, n+b), c)。
出力:
n = 2 m = 7
[編集] 条件演算子
条件演算子式は以下の形式を持ちます。
E1 ? E2 : E3
|
|||||||||
条件演算子の1つめに被演算子は bool に文脈的に変換されます。 1つめの被演算子の値の評価とすべての副作用がどちらも完了した後、その結果が true であった場合は2つめの被演算子が評価されます。 結果が falseであった場合は3つめの被演算子が評価されます。
条件式 E1 ? E2 : E3 の型と値カテゴリは以下のルールに従って決定されます。
E2
または E3
のいずれかが void 型の場合は、以下のいずれかが真でなければならず、そうでなければプログラムは ill-formed です。E2
または E3
のいずれか一方 (しかし両方ではない) が throw 式である (括弧で囲っていても構いません)。 条件演算子の結果は他方の式の型および値カテゴリを持ちます。 他方の式がビットフィールドの場合、結果はビットフィールドです。 このような条件演算子は C++14 以前の C++11 constexpr プログラミングでよく使用されていました。
std::string str = 2+2==4 ? "ok" : throw std::logic_error("2+2 != 4");
E2
および E3
がどちらも void 型である (両方が throw 式である場合も含みます)。 結果は void 型の prvalue です。
2+2==4 ? throw 123 : throw 456;
2) そうでなく、 E2 または E3 が同じ値カテゴリおよびそれぞれ型 cv1 T および cv2 T のビットフィールドの grvalue の場合、被演算子はこの節の残りに対して cv T であるとみなされます。 ただし cv は cv1 と cv2 の和です。
|
(C++14以上) |
E2
と E3
が異なる型であり、少なくとも一方がクラス型 (cv 修飾されていても構いません) であるか、または、どちらも同じ値カテゴリの grvalue であり、 cv 修飾を除いて同じ型の場合、以下で述べるように、それぞれの被演算子から、他方の被演算子によって決定されるターゲット型への、暗黙の変換のシーケンスの形成が試みられます。 このとき、メンバアクセス、被演算子がビットフィールドかどうか、変換関数が削除されているかどうかは無視されます。 (C++14以上) TX
型の被演算子 X
は、以下のように、他方の TY
型の被演算子 Y
のターゲット型に変換できます。Y
が lvalue の場合、ターゲット型は TY&
であり、その参照は lvalue に直接的に束縛しなければなりません。Y
が xvalue の場合、ターゲット型は TY&&
であり、その参照は直接的に束縛しなければなりません。Y
が prvalue の場合、または上記の変換シーケンスのいずれも形成できず、 TX
と TY
の少なくとも一方がクラス型 (cv 修飾されていても構いません) の場合、TX
と TY
が同じクラス型 (cv 修飾は無視します) であり、 TY
が TX
と同じまたはそれ以上に cv 修飾されている場合、ターゲット型は TY
です。TY
が TX
の基底クラスの場合、ターゲット型は TX
の cv 修飾を持つ TY
です。
struct A {}; struct B : A {}; using T = const B; A a = true ? A() : T(); // Y = A()、TY = A、X = T()、TX = const B。 ターゲット型 = const A。
E2
および E3
が同じ型かつ同じ値カテゴリの glvalue の場合、結果はその同じ型および値カテゴリであり、 E2
および E3
の少なくとも一方がビットフィールドであればビットフィールドです。E2
と E3
が同じ型でなく、どちらかがクラス型 (cv 修飾されていても構いません) の場合、被演算子を組み込みの型に変換することを試みるために下記の組み込みの候補を使用してオーバーロード解決が行われます。 このオーバーロード解決が失敗した場合、プログラムは ill-formed です。 そうでなければ、選択された変換が適用され、変換された被演算子がステップ6に対して元の値の場所で使用されます。E2
と E3
が今や同じ型である場合、結果は、 E1
の評価後に選択されたいずれかの被演算子からコピー初期化された一時オブジェクトを指す (C++17未満)オブジェクトを結果に持つ (C++17以上)、その型の pvalue です。E2
と E3
がどちらもポインタの場合、または一方がポインタで他方がヌルポインタ定数の場合、共通の型を得るためにポインタ変換および修飾子変換が適用され、その型が結果です。E2
と E3
がどちらもメンバポインタである場合、または一方がメンバポインタで他方がヌルポインタ定数の場合、共通の型を得るためにメンバポインタ変換および修飾子変換が適用され、その型が結果です。This section is incomplete Reason: any chance to make this more readable without losing the fine point? At the very least, a one-line micro-example for each bullet point would help tremendously |
昇格された算術型 L および R のすべての組について、およびポインタ、メンバポインタ、またはスコープ付き列挙型であるすべての型 P について、以下の関数シグネチャが上記のルールのステップ5で行われるオーバーロード解決に参加します。
LR operator?:(bool, L, R ); |
||
P operator?:(bool, P, P ); |
||
ただし LR は L
と R
に行われる通常の算術変換の結果です。 演算子「?:」はオーバーロードできす、これらの関数シグネチャはオーバーロード解決の目的のためにのみ存在しています。
条件演算子の戻り値の型は二項型特性 std::common_type としてもアクセス可能です。
#include <string> #include <iostream> struct Node { Node* next; int data; // deep-copying copy constructor Node(const Node& other) : next(other.next ? new Node(*other.next) : NULL) , data(other.data) {} Node(int d) : next(NULL), data(d) {} ~Node() { delete next ; } }; int main() { // simple rvalue example int n = 1>2 ? 10 : 11; // 1>2 is false, so n = 11 // simple lvalue example int m = 10; (n == m ? n : m) = 7; // n == m is false, so m = 7 std::cout << "n = " << n << "\nm = " << m; //output the result }
出力:
n = 11 m = 7
[編集] 標準ライブラリ
標準ライブラリの多くのクラスが関数オブジェクトとして使用するために operator()
をオーバーロードしています。
オブジェクトまたは配列を削除します ( std::default_delete<T> のパブリックメンバ関数)
| |
2つの引数の和を返します ( std::plus<T> のパブリックメンバ関数)
| |
2つの引数の差を返します ( std::minus<T> のパブリックメンバ関数)
| |
2つの引数の積を返します ( std::multiplies<T> のパブリックメンバ関数)
| |
第1引数を第2引数で割った結果を返します ( std::divides<T> のパブリックメンバ関数)
| |
第1引数を第2引数で割った余りを返します ( std::modulus<T> のパブリックメンバ関数)
| |
引数の否定を返します ( std::negate<T> のパブリックメンバ関数)
| |
引数が等しいかどうか調べます ( std::equal_to<T> のパブリックメンバ関数)
| |
引数が等しくないかどうか調べます ( std::not_equal_to<T> のパブリックメンバ関数)
| |
第1引数が第2引数より大きいかどうか調べます ( std::greater<T> のパブリックメンバ関数)
| |
第1引数が第2引数より小さいかどうか調べます ( std::less<T> のパブリックメンバ関数)
| |
第1引数が第2引数より大きいまたは等しいかどうか調べます ( std::greater_equal<T> のパブリックメンバ関数)
| |
第1引数が第2引数より小さいまたは等しいかどうか調べます ( std::less_equal<T> のパブリックメンバ関数)
| |
2つの引数の論理積を返します ( std::logical_and<T> のパブリックメンバ関数)
| |
2つの引数の論理和を返します ( std::logical_or<T> のパブリックメンバ関数)
| |
引数の論理否定を返します ( std::logical_not<T> のパブリックメンバ関数)
| |
2つの引数のビット単位の論理積の結果を返します ( std::bit_and<T> のパブリックメンバ関数)
| |
2つの引数のビット単位の論理和の結果を返します ( std::bit_or<T> のパブリックメンバ関数)
| |
2つの引数のビット単位の排他的論理和の結果を返します ( std::bit_xor<T> のパブリックメンバ関数)
| |
格納されている述語の呼び出しの結果の論理否定を返します ( std::unary_negate<Predicate> のパブリックメンバ関数)
| |
格納されている述語の呼び出しの結果の論理否定を返します ( std::binary_negate<Predicate> のパブリックメンバ関数)
| |
格納されている関数を呼びます ( std::reference_wrapper<T> のパブリックメンバ関数)
| |
ターゲットを呼び出します ( std::function<R(Args...)> のパブリックメンバ関数)
| |
このロケールの照合ファセットを用いて2つの文字列を辞書的に比較します ( std::locale のパブリックメンバ関数)
| |
2つの value_type 型の値を比較します ( std::map<Key,T,Compare,Allocator>::value_compare のパブリックメンバ関数)
| |
2つの value_type 型の値を比較します ( std::multimap<Key,T,Compare,Allocator>::value_compare のパブリックメンバ関数)
| |
関数を実行します ( std::packaged_task<R(Args...)> のパブリックメンバ関数)
| |
エンジンの状態を進めて生成された値を返します ( std::linear_congruential_engine<UIntType,a,c,m> のパブリックメンバ関数)
| |
分布の次の乱数を生成します ( std::uniform_int_distribution<IntType> のパブリックメンバ関数)
|
コンマ演算子は標準ライブラリのどのクラスによってもオーバーロードされていません。 boost ライブラリは boost.assign、 boost.spirit などのライブラリで operator,
を使用しています。 データベースアクセスライブラリ SOCI も operator,
をオーバーロードしています。
[編集] 欠陥報告
以下の動作変更欠陥報告は以前に発行された C++ 標準に遡って適用されました。
DR | 適用先 | 発行時の動作 | 正しい動作 |
---|---|---|---|
CWG 1550 | C++98 | parenthesized throw-expression not allowed in ?: if other operand is non-void | parenthesized throw-expressions accepted |
CWG 1560 | C++98 | void operand in ?: caused gratuitous l-to-r conversion on the other operand, always resulting in rvalue |
?:with a void can be lvalue |
CWG 1932 | C++14 | same-type bit fields were missing in ?: | handled by underlying types |
CWG 1895 | C++14 | unclear if deleted or inaccessible conversion function prevents conversion in ?:, and conversions from base class to derived class prvalue were not considered |
handled like overload resolution |
[編集] 関連項目
一般的な演算子 | ||||||
---|---|---|---|---|---|---|
代入 | インクリメント デクリメント |
算術 | 論理 | 比較 | メンバアクセス | その他 |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
特殊な演算子 | ||||||
static_cast は型を別の関連する型に変換します。 |
その他の演算子 の C言語リファレンス
|