Other operators
|
演算子名
名称 |
構文 | オーバーロード可能 | プロトタイプ例 ( class T の場合) | |
|---|---|---|---|---|
| クラス定義内 | クラス定義外 | |||
| 関数呼び出し |
a(a1, a2)
|
可 | R T :: operator ( ) ( Arg1 & a1, Arg2 & a2, ... ) ; | 該当なし |
| コンマ演算子 |
a, b
|
可 | T2 & T :: operator , ( T2 & b ) ; | T2 & operator, ( const T & a, T2 & b ) ; |
| 条件演算子 |
a ? b : c
|
不可 | 該当なし | 該当なし |
関数呼び出し 演算子は、任意のオブジェクトに関数セマンティクスを提供します。
条件演算子 (通称 三項条件演算子 )は、最初の式のブール値をチェックし、その結果に応じて2番目または3番目の式を評価して返します。
目次 |
組み込み関数呼び出し演算子
関数呼び出し式は以下の形式を持ちます:
関数
(
arg1
,
arg2
,
arg3
,
...
)
|
|||||||||
| function | - | 関数型または関数ポインタ型の式 |
arg1
,
arg2
,
arg3
,
...
|
- | 任意の式の空でもよいリスト または 波括弧で囲まれた初期化子リスト (C++11以降) 、ただし曖昧さを避けるためトップレベルでのカンマ演算子は許可されない |
非メンバー関数または staticメンバー関数 の呼び出しにおいて、 function は関数を参照する左辺値(この場合 function-to-pointer conversion は抑制される)、または関数ポインタ型のprvalueとなり得ます。
function で指定された関数(またはメンバー)名はオーバーロード可能であり、 overload resolution ルールを使用してどのオーバーロードを呼び出すかが決定されます。
function がメンバ関数を指定する場合、それは仮想関数である可能性があり、その場合、その関数の最終オーバーライダーが実行時に動的ディスパッチを使用して呼び出されます。
各関数パラメータは、必要に応じて 暗黙変換 が行われた後、対応する引数で初期化されます。
- 対応する引数がない場合、対応する デフォルト引数 が使用され、それも存在しない場合、プログラムは不適格となる。
- 呼び出しがメンバ関数に対するものである場合、現在のオブジェクトへの this ポインタは、関数が期待する this ポインタへ明示的キャストと同様に変換される。
- 各パラメータの初期化と破棄は、関数呼び出しが現れる 完全式 のコンテキストで発生する。これは例えば、パラメータのコンストラクタまたはデストラクタが例外をスローした場合、呼び出された関数の 関数 try ブロック は考慮されないことを意味する。
関数が可変引数関数の場合、 デフォルト引数プロモーション が省略記号パラメータにマッチする全ての引数に適用されます。
パラメータが、それが定義されている関数の終了時に破棄されるか、囲んでいる完全式の終了時に破棄されるかは実装定義です。パラメータは常に構築の逆順で破棄されます。
関数呼び出し式の戻り値の型は、選択された関数の戻り値の型であり、( virtual キーワードを無視した)静的バインディングを使用して決定されます。実際に呼び出されるオーバーライド関数が異なる型を返す場合でも同様です。これにより、オーバーライド関数が基底関数が返す戻り値の型から派生したクラスへのポインタや参照を返すことが可能になります。つまり、C++は 共変戻り値型 をサポートしています。 function がデストラクタを指定する場合、戻り値の型は void です。
|
クラス型
一時オブジェクトはそれぞれ関数引数または戻り値から構築され、関数のパラメータまたは戻りオブジェクトは、非削除されたトリビアルコンストラクタを使用して一時オブジェクトをコピーするかのように初期化されます(たとえそのコンストラクタがアクセス不能であるか、オーバーロード解決によってオブジェクトのコピーまたはムーブを実行するために選択されない場合でも)。 これにより、 std::complex や std::span などの小さなクラス型のオブジェクトを、レジスタ内で関数に渡したり関数から返したりすることが可能になります。 |
(C++17以降) |
関数呼び出し式の値カテゴリは、関数がlvalue参照または関数へのrvalue参照を返す場合はlvalue、関数がオブジェクトへのrvalue参照を返す場合はxvalue、それ以外の場合はprvalueとなります。関数呼び出し式がオブジェクト型のprvalueである場合、それは
complete type
を持たなければならない(ただし、
decltype
のオペランドとして使用される場合(または
built-in comma operator
の右オペランドであり、それが
decltype
のオペランドである場合を除く)
(C++11以降)
。
|
呼び出された関数が正常に終了した場合、その関数のすべての
事後条件アサーション
は
順番に評価
されます。実装が結果値を保持するために
一時オブジェクト
を導入する場合、各事後条件アサーションの評価
|
(C++26以降) |
関数呼び出し式は構文的に値初期化
T
(
)
や、
関数形式キャスト
式
T
(
A1
)
および一時オブジェクトの直接初期化
T
(
A1, A2, A3, ...
)
と類似しています。ここで
T
は型名です。
#include <cstdio> struct S { int f1(double d) { return printf("%f \n", d); // 可変引数関数呼び出し } int f2() { return f1(7); // メンバー関数呼び出し、this->f1()と同じ // 整数引数がdoubleに変換される } }; void f() { puts("function called"); // 関数呼び出し } int main() { f(); // 関数呼び出し S s; s.f2(); // メンバー関数呼び出し }
出力:
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 ) 。
|
括弧で囲まれていないカンマ式を subscript operator の第2(右)引数として使用することは非推奨です。 例えば、 a [ b, c ] は非推奨であり、 a [ ( b, c ) ] は非推奨ではありません。 |
(C++20以降)
(C++23まで) |
|
括弧で囲まれていないカンマ式は subscript operator の第2(右)引数として使用できません。例えば、 a [ b, c ] は不適格であるか、または a. operator [ ] ( b, c ) と同等です。 カンマ式をsubscriptとして使用する場合は括弧が必要です。例えば、 a [ ( b, c ) ] のようにします。 |
(C++23以降) |
#include <iostream> int main() { // コンマは、言語文法が単一の式のみを許可する場所で // 複数の式を実行するためによく使用される: // * forループの第3コンポーネント内 for (int i = 0, j = 10; i <= j; ++i, --j) // ^リスト区切り文字 ^コンマ演算子 std::cout << "i = " << i << " j = " << j << '\n'; // * return文内 // return log("an error!"), -1; // * 初期化式内 // MyClass(const Arg& arg) // : member{ throws_if_bad(arg), arg } // など // コンマ演算子は連結可能;最後(最も右)の式の結果が // チェーン全体の結果となる: int n = 1; int m = (++n, std::cout << "n = " << n << '\n', ++n, 2 * n); // mは現在6 std::cout << "m = " << (++m, m) << '\n'; }
出力:
i = 0 j = 10 i = 1 j = 9 i = 2 j = 8 i = 3 j = 7 i = 4 j = 6 i = 5 j = 5 n = 2 m = 7
条件演算子
条件演算子の式は以下の形式を持ちます
E1
?
E2
:
E3
|
|||||||||
E1 が評価され、 文脈に応じた変換 によって bool に変換される。結果が true の場合、条件式の結果は E2 の値となる。それ以外の場合、条件式の結果は E3 の値となる。
条件式 E1 ? E2 : E3 の型と値カテゴリは以下のように決定されます:
Stage 1
E2 と E3 の両方が型 void である場合、結果は型 void の 右辺値 (C++11まで) 純粋右辺値 (C++11以降) です。
E2 と E3 のうち厳密に一方が型 void である場合:
- そのオペランドの型が void であり、かつ(括弧で囲まれた可能性のある) throw 式 である場合、結果はもう一方のオペランドの型と値カテゴリを持つ [1] 。もう一方のオペランドが ビットフィールド である場合、結果もビットフィールドとなる。
- それ以外の場合、プログラムは不適格となる。
E2 と E3 のいずれも void 型でない場合、次の段階に進みます。
2 + 2 == 4 ? throw 123 : throw 456; // 結果の型は「void」 2 + 2 != 4 ? "OK" : throw "error"; // 結果の型は「const char[3]」 // 例外が常にスローされる場合でも
ステージ2
E2
または
E3
が
左辺値ビットフィールド
(C++11まで)
同じ値カテゴリのglvalueビットフィールド
(C++11以降)
であり、それぞれ型
cv1
T
と
cv2
T
を持つ場合、オペランドは残りの処理において型
cv
T
を持つものと見なされます。ここで
cv
は
cv1
と
cv2
の和集合です。
E2 と E3 が異なる型を持ち、以下のいずれかの条件が満たされる場合、ステージ3に進みます:
- E2 と E3 の少なくとも一方が(CV修飾されている可能性のある)クラス型である。
- E2 と E3 の両方が 同じ型の左辺値 (C++11まで) 同じ値カテゴリおよび同じ型のglvalue (C++11以降) であり、CV修飾を除いて同一の型である。
それ以外の場合は、ステージ4に進みます。
ステージ3
オペランド式
X
の型
TX
から、オペランド式
Y
の型
TY
に関連する
ターゲット型
への
暗黙変換シーケンス
[2]
が以下のように形成されます:
-
Y
が左辺値の場合、対象型は
TY&となるが、暗黙変換シーケンスはその参照が 直接バインド する場合にのみ形成可能である 左辺値へ (C++11まで) glvalueへ (C++11以降) 。
|
(C++11以降) |
-
Y
が
右辺値
(C++11まで)
純粋右辺値
(C++11以降)
である場合、または上記の変換シーケンスが形成できず、かつ
TXとTYの少なくとも一方が(CV修飾可能性のある)クラス型である場合:-
TXとTYが同じクラス型(CV修飾を無視)の場合:-
TYがTXと同等以上のCV修飾を持つ場合、対象型はTYとなる。 - それ以外の場合、変換シーケンスは形成されない。
-
-
それ以外の場合、
TYがTXの基底クラスである場合、対象型はTXのCV修飾子を持つTYとなる。 - それ以外の場合、対象型は Z の型となる。ここで Z は、 Y に左辺値から右辺値、配列からポインタ、関数からポインタへの 標準変換 を適用した後の値である。
-
- それ以外の場合、変換シーケンスは形成されない。
このプロセスでは、 E2 から E3 に対して決定されたターゲット型への暗黙変換シーケンスが形成可能かどうか、およびその逆が判定されます。
- 変換シーケンスが形成できない場合、次の段階に進む。
-
ちょうど1つの変換シーケンスが形成できる場合:
- 変換シーケンスが曖昧な場合、プログラムは不適格となる。
- それ以外の場合、その変換が選択された被演算子に適用され、変換された被演算子が元の被演算子の代わりに残りの処理で使用され、次の段階に進む。
- 両方のシーケンスが形成できる場合、プログラムは不適格となる。
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
ステージ4
|
E2 と E3 が同じ型のlvalueである場合、結果はその型のlvalueとなり、 E2 と E3 の少なくとも一方がビットフィールドである場合は、結果もビットフィールドとなる。 |
(C++11まで) |
|
E2 と E3 が同じ型と同じ値カテゴリのglvalueである場合、結果は同じ型と値カテゴリを持ち、 E2 と E3 の少なくとも一方がビットフィールドである場合は、結果もビットフィールドとなる。 |
(C++11以降) |
それ以外の場合、結果は an rvalue (until C++11) a prvalue (since C++11) です。
- E2 と E3 が同じ型を持たず、かつどちらかが(cv修飾されている可能性のある)クラス型を持つ場合、ステージ5に進む。
- それ以外の場合、ステージ6に進む。
ステージ5
オーバーロード解決 は、 組み込み候補 を使用して実行され、オペランドを組み込み型に変換しようと試みます:
- オーバーロード解決が失敗した場合、プログラムは不適格となる。
- それ以外の場合、選択された変換が適用され、変換された被演算子は元の被演算子の代わりに残りの処理で使用される。次の段階に進む。
ステージ6
配列からポインタへの変換および関数からポインタへの変換は、(変換後の可能性がある) E2 および E3 に適用されます。これらの変換後、以下の条件の少なくとも1つが満たされなければならず、そうでない場合プログラムは不適格となります:
- E2 と E3 が同じ型を持つ場合。この場合、結果はその型となり、選択されたオペランドを用いて コピー初期化 されます。
- E2 と E3 の両方が算術型または列挙型を持つ場合。この場合、 通常の算術変換 が適用されて共通の型に変換され、結果はその型となります。
- E2 と E3 の少なくとも一方がポインタの場合。この場合、左辺値から右辺値への変換、ポインタ 、関数ポインタ (C++17以降) 変換、および修飾変換が適用されて 複合ポインタ型 に変換され、結果はその型となります。
- E2 と E3 の少なくとも一方がメンバポインタの場合。この場合、左辺値から右辺値への変換、メンバポインタ 、関数ポインタ (C++17以降) 変換、および修飾変換が適用されて 複合ポインタ型 に変換され、結果はその型となります。
|
(C++11以降) |
int* intPtr; using Mixed = decltype(true ? nullptr : intPtr); static_assert(std::is_same_v<Mixed, int*>); // nullptrがint*型になる struct A { int* m_ptr; } a; int* A::* memPtr = &A::m_ptr; // memPtrはAのメンバm_ptrへのポインタ // memPtrによりnullptrはAのメンバm_ptrへのポインタ型となる static_assert(std::is_same_v<decltype(false ? memPtr : nullptr), int*A::*>); // a.*memPtrはintへのポインタとなり、nullptrもintへのポインタとなる static_assert(std::is_same_v<decltype(false ? a.*memPtr : nullptr), int*>);
- ↑ このような条件演算子は、C++14以前のC++11 constexprプログラミング で一般的に使用されていました。
- ↑ メンバーアクセス 、変換関数が削除されているかどうか (C++11以降) 、およびオペランドがビットフィールドかどうかは無視されます。
|
条件演算子の結果型は、二項型特性 std::common_type としてもアクセス可能です。 |
(C++11以降) |
オーバーロード
すべての昇格された算術型のペア
L
と
R
、およびすべての型
P
について、
P
がポインタ、メンバへのポインタ、またはスコープ付き列挙型である場合、以下の関数シグネチャがオーバーロード解決に参加します:
|
LR 演算子
?:
(
bool
, L, R
)
;
|
||
|
P 演算子
?:
(
bool
, P, P
)
;
|
||
LRは、
通常の算術変換
が
L
と
R
に対して実行された結果です。
演算子「
?:
」はオーバーロードできません。これらの関数シグネチャはオーバーロード解決の目的でのみ存在します。
#include <iostream> #include <string> struct Node { Node* next; int data; // ディープコピーを行うコピーコンストラクタ 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() { // 単純な右辺値の例 int n = 1 > 2 ? 10 : 11; // 1 > 2 は false なので n = 11 // 単純な左辺値の例 int m = 10; (n == m ? n : m) = 7; // n == m は false なので m = 7 // 結果を出力 std::cout << "n = " << n << "\nm = " << m; }
出力:
n = 11 m = 7
標準ライブラリ
標準ライブラリの多くのクラスは、関数オブジェクトとして使用するために
operator()
をオーバーロードしています。
|
オブジェクトまたは配列を削除する
(
std::default_delete<T>
の公開メンバー関数)
|
|
|
2つの引数の合計を返す
(
std::plus<T>
の公開メンバ関数)
|
|
|
2つの引数の差を返す
(
std::minus<T>
の公開メンバ関数)
|
|
|
2つの引数の積を返す
(
std::multiplies<T>
の公開メンバ関数)
|
|
|
最初の引数を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>
の公開メンバ関数
)
|
|
|
最初の引数が2番目の引数以下かどうかをチェックする
(
std::less_equal<T>
の公開メンバ関数)
|
|
|
2つの引数の論理積を返す
(
std::logical_and<T>
の公開メンバー関数)
|
|
|
2つの引数の論理和を返す
(
std::logical_or<T>
の公開メンバー関数)
|
|
|
引数の論理否定を返す
(
std::logical_not<T>
の公開メンバ関数)
|
|
|
2つの引数のビット単位ANDの結果を返す
(
std::bit_and<T>
の公開メンバー関数)
|
|
|
2つの引数のビット単位ORの結果を返す
(
std::bit_or<T>
の公開メンバー関数)
|
|
|
2つの引数のビット単位XORの結果を返す
(
std::bit_xor<T>
の公開メンバ関数)
|
|
|
格納された述語の呼び出し結果の論理否定を返す
(
std::unary_negate<Predicate>
の公開メンバ関数)
|
|
|
格納された述語の呼び出し結果の論理否定を返す
(
std::binary_negate<Predicate>
の公開メンバ関数)
|
|
|
格納された関数を呼び出す
(
std::reference_wrapper<T>
の公開メンバ関数)
|
|
|
ターゲットを呼び出す
(
std::function<R(Args...)>
の公開メンバ関数)
|
|
|
ターゲットを呼び出す
(
std::move_only_function
の公開メンバ関数)
|
|
|
ターゲットを呼び出す
(
std::copyable_function
の公開メンバ関数)
|
|
|
コルーチンの実行を再開する
(
std::coroutine_handle<Promise>
の公開メンバ関数)
|
|
|
このロケールの照合ファセットを使用して2つの文字列を辞書順に比較する
(
std::locale
の公開メンバ関数)
|
|
value_type
型の2つの値を比較する
(
std::map<Key,T,Compare,Allocator>::value_compare
の
公開メンバ関数)
|
|
value_type
型の2つの値を比較する
(
std::multimap<Key,T,Compare,Allocator>::value_compare
の
公開メンバ関数)
|
|
|
関数を実行する
(
std::packaged_task<R(Args...)>
の公開メンバ関数)
|
|
|
エンジンの状態を進め、生成された値を返す
(
std::linear_congruential_engine<UIntType,a,c,m>
の公開メンバ関数)
|
|
|
(C++11)
|
分布における次の乱数を生成する
(
std::uniform_int_distribution<IntType>
の公開メンバ関数)
|
標準ライブラリでは、どのクラスもコンマ演算子をオーバーロードしていません。Boostライブラリでは operator, を boost.assign 、 boost.spirit およびその他のライブラリで使用しています。データベースアクセスライブラリの SOCI も operator, をオーバーロードしています。
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用バージョン | 公開時の仕様 | 修正後の仕様 |
|---|---|---|---|
| CWG 446 | C++98 |
条件演算子における左辺値から右辺値への変換で一時オブジェクトが
作成されるかどうかが未規定であった |
演算子がクラス右辺値を返す場合、
常に一時オブジェクトを作成する |
| CWG 462 | C++98 |
コンマ演算子の第2オペランドが一時オブジェクトの場合、
コンマ式の結果が参照に束縛されるときにその寿命が 延長されるかどうかが未規定であった |
この場合のコンマ式の結果は
一時オブジェクトとなる (したがって寿命が延長される) |
| CWG 587 | C++98 |
条件演算子の第2および第3オペランドがCV修飾のみが異なる
同じ型の左辺値の場合、これらのオペランドがクラス型の場合は 結果が左辺値、それ以外の場合は右辺値となっていた |
この場合の結果は常に
左辺値となる |
| CWG 1029 | C++98 | デストラクタ呼び出しの型が未規定であった | void と規定 |
| CWG 1550 | C++98 |
括弧で囲まれた
throw
式は、他のオペランドが非
void
の場合、
条件式で許可されていなかった |
許可される |
| CWG 1560 | C++98 |
条件演算子の
void
オペランドが他のオペランドに
不要な左辺値から右辺値への変換を引き起こし、 常に右辺値となっていた |
void
を含む条件式は
左辺値となり得る |
| CWG 1642 | C++98 |
関数呼び出し式における
関数
式は
関数ポインタの左辺値となり得た |
許可されない |
| CWG 1805 | C++98 |
暗黙の変換シーケンスの対象型を決定する際、
Y から Z への変換方法が不明確であった |
明確化された |
| CWG 1895 |
C++98
C++11 |
削除済み(C++11)またはアクセス不能(C++98)の
変換関数が条件式での変換を妨げるかどうかが不明確で、 基底クラスから派生クラスへの純粋右辺値の変換が 考慮されていなかった |
オーバーロード解決と
同様に扱われる |
| CWG 1932 | C++98 | 同じ型のビットフィールドが条件式で欠落していた | 基底型によって扱われる |
| CWG 2226 | C++11 |
条件演算子の他のオペランドの対象型を決定する際、
そのオペランドが左辺値の場合、参照が xvalueに束縛できなかった |
許可される |
| CWG 2283 | C++17 |
関数呼び出し演算子の型完全性要件が
P0135R1 によって誤って削除された |
要件が復元された |
| CWG 2321 | C++98 |
条件演算子の他のオペランドの対象型を決定する際、
派生クラス型からより少ないCV修飾の 基底クラス型に変換できなかった |
派生クラスオペランドからの
CV修飾を持つ基底クラス型への 変換が許可される |
| CWG 2715 | C++98 |
各パラメータの初期化と破棄は呼び出し元関数の
コンテキスト内で発生するが、その関数が 存在しない可能性がある [1] |
それを囲む完全式の
コンテキスト内で発生する |
| CWG 2850 | C++98 | パラメータの破棄順序が不明確であった | 明確化された |
| CWG 2865 | C++98 |
TX
と
TY
が同じクラス型で
TX
が
TY
より
多くのCV修飾を持つ場合でも、純粋右辺値 Y からの 暗黙の変換シーケンスが形成され得た |
この場合、変換シーケンスは
形成されない |
| CWG 2906 | C++98 |
条件演算子の右辺値結果の場合に左辺値から右辺値への
変換が無条件に適用されていた |
一部の場合にのみ適用される |
- ↑ 例えば、関数は名前空間スコープ変数の初期化子で呼び出すことができますが、この文脈には「呼び出し元関数」は存在しません。
関連項目
| 一般的な演算子 | ||||||
|---|---|---|---|---|---|---|
| 代入 |
インクリメント
デクリメント |
算術 | 論理 | 比較 |
メンバー
アクセス |
その他 |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
...
]
|
関数呼び出し
a ( ... ) |
|
カンマ
a, b |
||||||
|
条件演算子
a ? b : c |
||||||
| 特殊演算子 | ||||||
|
static_cast
関連する型間で変換を行う
|
||||||
|
C documentation
for
Other operators
|