Member access operators
そのオペランドのメンバーにアクセスします。
| 演算子名 | 構文 | オーバーロード 可能 | プロトタイプ例 ( class T の場合) | |
|---|---|---|---|---|
| クラス定義内 | クラス定義外 | |||
| 添字 | a [ b ] | 可 | R & T :: operator [ ] ( S b ) ; | 該当なし |
| a [ ... ] (C++23以降) | R & T :: operator [ ] ( ... ) ; | |||
| 間接参照 | * a | 可 | R & T :: operator * ( ) ; | R & operator * ( T a ) ; |
| アドレス取得 | & a | 可 | R * T :: operator & ( ) ; | R * operator & ( T a ) ; |
| オブジェクトのメンバ | a. b | 不可 | 該当なし | 該当なし |
| ポインタのメンバ | a - > b | 可 | R * T :: operator - > ( ) ; | 該当なし |
| オブジェクトのメンバへのポインタ | a. * b | 不可 | 該当なし | 該当なし |
| ポインタのメンバへのポインタ | a - > * b | 可 | R & T :: operator - > * ( S b ) ; | R & operator - > * ( T a, S b ) ; |
|
||||
目次 |
説明
組み込みの 添字演算子 は、 pointer または array オペランドによって指されるオブジェクトへのアクセスを提供します。
組み込みの 間接参照 演算子は、ポインタオペランドが指すオブジェクトまたは関数へのアクセスを提供します。
組み込みの address-of 演算子は、オブジェクトまたは関数オペランドを指すポインタを作成します。
オブジェクトのメンバ および オブジェクトのメンバへのポインタ 演算子は、オブジェクトオペランドのデータメンバまたはメンバ関数へのアクセスを提供します。
組み込みの メンバポインタ および メンバポインタへのポインタ 演算子は、ポインタオペランドが指すクラスのデータメンバまたはメンバ関数へのアクセスを提供します。
組み込み添字演算子
添字演算子の式は以下の形式を持ちます
expr1
[
expr2
]
|
(1) | ||||||||
expr1
[{
expr
, ...
}]
|
(2) | (C++11以降) | |||||||
expr1
[
expr2
,
expr
, ...
]
|
(3) | (C++23以降) | |||||||
T
型の配列」のglvalue、または「
T
へのポインタ」のprvalueでなければなりません。もう一方の式(それぞれ
expr2
または
expr1
)は、非スコープ列挙型または整数型のprvalueでなければなりません。この式の結果の型は
T
です。
expr2
は括弧で囲まれていない
コンマ演算子
であってはなりません。
(C++23以降)
組み込みの添字式 E1 [ E2 ] は、その値カテゴリ(下記参照) および 評価順序 (C++17以降) を除き、式 * ( E1 + E2 ) と完全に同一です:ポインタオペランド(配列からポインタへの変換の結果である可能性があり、何らかの配列の要素または末尾の次を指していなければならない)は、 ポインタ算術 の規則に従って同じ配列の別の要素を指すように調整され、その後デリファレンスされます。
配列に適用される場合、添字式は lvalue 配列がlvalueの場合はlvalueとなり、そうでない場合は xvalue となる (C++11以降) 。
ポインタに適用される場合、添字式は常に左辺値です。
型
T
は、
incomplete type
であってはなりません。たとえ
T
のサイズや内部構造が
&
x
[
0
]
のように使用されない場合でも同様です。
|
括弧で囲まれていない comma expression を添字演算子の第2(右)引数として使用することは非推奨です。 例えば、 a [ b, c ] は非推奨であり、 a [ ( b, c ) ] は非推奨ではありません。 |
(C++20以降)
(C++23まで) |
|
括弧で囲まれていない comma expression は添字演算子の第2(右)引数として使用できません。例えば、 a [ b, c ] は不適格であるか、 a. operator [ ] ( b, c ) と同等です。 カンマ式を添字として使用するには括弧が必要です。例: a [ ( b, c ) ] 。 |
(C++23以降) |
ユーザー定義演算子に対するオーバーロード解決
において、あらゆるオブジェクト型
T
(CV修飾されている可能性あり)に対して、以下の関数シグネチャがオーバーロード解決に参加します:
|
T
&
operator
[
]
(
T
*
,
std::
ptrdiff_t
)
;
|
||
|
T
&
operator
[
]
(
std::
ptrdiff_t
, T
*
)
;
|
||
#include <iostream> #include <map> #include <string> int main() { int a[4] = {1, 2, 3, 4}; int* p = &a[2]; std::cout << p[1] << p[-1] << 1[p] << (-1)[p] << '\n'; std::map<std::pair<int, int>, std::string> m; m[{1, 2}] = "abc"; // uses the [{...}] version }
出力:
4242
組み込み間接演算子
間接演算子の式は以下の形式を持ちます
*
expr
|
|||||||||
`タグ内のテキストは翻訳せず、元のフォーマットを保持しました。`expr`はC++の式を表す用語のため、翻訳対象外としています。
組み込みの間接参照演算子のオペランドは、オブジェクトへのポインタまたは関数へのポインタでなければならず、結果は
expr
が指すオブジェクトまたは関数を参照する左辺値です。
expr
が実際にオブジェクトまたは関数を指していない場合、動作は未定義です(
typeid
で指定される場合を除く)。
( cv 修飾される可能性のある) void へのポインタは間接参照できません。他の不完全型へのポインタは間接参照できますが、結果の左辺値は不完全型の左辺値が許可される文脈(例えば参照の初期化時)でのみ使用できます。
ユーザー定義演算子に対するオーバーロード解決
において、オブジェクト型(CV修飾可能性あり)または関数型(const修飾および参照修飾なし)であるすべての型
T
について、以下の関数シグネチャがオーバーロード解決に参加します:
|
T
&
operator
*
(
T
*
)
;
|
||
#include <iostream> int f() { return 42; } int main() { int n = 1; int* pn = &n; int& r = *pn; // lvalueは参照に束縛可能 int m = *pn; // 間接参照 + lvalue-to-rvalue変換 int (*fp)() = &f; int (&fr)() = *fp; // 関数lvalueは参照に束縛可能 [](...){}(r, m, fr); // 未使用変数警告を抑制 }
組み込みアドレス取得演算子
アドレス取得演算子の式は以下の形式を持ちます
&
expr
|
(1) | ||||||||
&
class
::
member
|
(2) | ||||||||
T
のlvalue式である場合、
operator&
は同じcv修飾を持つ
T*
型のprvalueを生成して返し、これは被演算子によって指定されたオブジェクトまたは関数を指します。被演算子が不完全型を持つ場合、ポインタは形成できますが、その不完全型が独自の
operator
&
を定義するクラスである場合、組み込み演算子とオーバーロードのどちらが使用されるかは未規定です。ユーザー定義の
operator
&
を持つ型の被演算子については、
std::addressof
を使用して真のポインタを取得できます。
C99以降のCバージョンとは異なり、単項
operator
*
の結果に適用された単項
operator
&
に対する特別なケースはないことに注意してください。
|
expr
が
explicit object member function
を指す場合、
expr
は
qualified identifier
でなければなりません。explicit object member function を指す非修飾識別子に
|
(C++23以降) |
C
における型
T
の
pointer to member function
または
pointer to data member
を表すprvalueとなる。
&
member
も
C
::
member
も、さらに
&
(
C
::
member
)
も、pointer to memberの初期化に使用できないことに注意。
ユーザー定義演算子に対するオーバーロード解決 において、この演算子は追加の関数シグネチャを導入しません:組み込みのアドレス取得演算子は、有効な関数であるオーバーロードされた operator & が存在する場合には適用されません。
void f(int) {} void f(double) {} struct A { int i; }; struct B { void f(); }; int main() { int n = 1; int* pn = &n; // ポインタ int* pn2 = &*pn; // pn2 == pn int A::* mp = &A::i; // データメンバへのポインタ void (B::*mpf)() = &B::f; // メンバ関数へのポインタ void (*pf)(int) = &f; // 初期化コンテキストによるオーバーロード解決 // auto pf2 = &f; // エラー: 曖昧なオーバーロード関数型 auto pf2 = static_cast<void (*)(int)>(&f); // キャストによるオーバーロード解決 }
組み込みメンバーアクセス演算子
メンバアクセス演算子の式は以下の形式を持ちます
expr
.template
(オプション)
id-expr
|
(1) | ||||||||
expr
->template
(オプション)
id-expr
|
(2) | ||||||||
expr
.
擬似デストラクタ
|
(3) | ||||||||
expr
->
擬似デストラクタ
|
(4) | ||||||||
T*
へのポインタ式でなければなりません。
id-expr
は、
T
または
T
の明確かつアクセス可能な基底クラス
B
のデータメンバまたはメンバ関数の名前である(形式的には、
識別子式
で名前付けされたもの)(例:
E1.
E2
または
E1
-
>
E2
)。オプションで
修飾
可能(例:
E1.
B
::
E2
または
E1
-
>
B
::
E2
)。オプションで
template
曖昧性除去子
を使用可能(例:
E1.
template
E2
または
E1
-
>
template
E2
)。
ユーザー定義の operator - > が呼び出された場合、 operator - > は結果の値に対して再帰的に繰り返し呼び出され、プレーンなポインタを返す operator - > に到達するまで続きます。その後、そのポインタに対して組み込みのセマンティクスが適用されます。
式 E1 - > E2 は組み込み型に対して ( * E1 ) . E2 と完全に等価です。そのため、以下の規則では E1. E2 のみを扱います。
式 E1. E2 において:
-
E2
が参照型
T&またはT&&(C++11以降) の場合、結果はその参照が束縛されているオブジェクトまたは関数を指す型Tの左辺値である。 -
それ以外の場合、
E2
の型を
Tとすると、結果はそのstaticデータメンバを指す型Tの左辺値である。
-
E2
が参照型
T&またはT&&(C++11以降) の場合、結果は対応する参照メンバが E1 で束縛されているオブジェクトまたは関数を指す型Tの左辺値である。 - それ以外の場合、 E1 が左辺値であれば、結果は E1 のその非静的データメンバを指す左辺値である。
- それ以外の場合( E1 が 右辺値 (C++17まで) xvalue(prvalueから 実体化 される可能性あり) (C++17以降) の場合)、結果は 右辺値 (C++11まで) xvalue (C++11以降) であり、 E1 のその非静的データメンバを指す。
- E2 が static member function である場合、結果はそのstatic member functionを指す左辺値となる。本質的に、この場合 E1 は評価され破棄される。
- それ以外の場合( E2 が non-static member function である場合)、結果は E1 のそのnon-static member functionを指すprvalueとなる。
T
とすると、結果は列挙子の値を持つ型
T
の
右辺値
(C++11まで)
純粋右辺値
(C++11以降)
である。
~
に続いて同じ型(CV修飾を除く)を指定する
型名
または
decltype指定子
であり、任意で
修飾
されている場合、結果は関数呼び出し演算子の左側オペランドとしてのみ使用でき、他の目的には使用できない特殊な種類のprvalueとなる。
operator. はオーバーロードできず、 operator - > については、 ユーザー定義演算子に対するオーバーロード解決 において、組み込み演算子は追加の関数シグネチャを導入しません:有効な関数であるオーバーロードされた operator - > が存在する場合、組み込みの operator - > は適用されません。
#include <cassert> #include <iostream> #include <memory> struct P { template<typename T> static T* ptr() { return new T; } }; template<typename T> struct A { A(int n): n(n) {} int n; static int sn; int f() { return 10 + n; } static int sf() { return 4; } class B {}; enum E {RED = 1, BLUE = 2}; void g() { typedef int U; // 依存テンプレートメンバーにはtemplateキーワードが必要 int* p = T().template ptr<U>(); p->~U(); // Uはint、intの擬似デストラクタを呼び出す delete p; } }; template<> int A<P>::sn = 2; struct UPtrWrapper { std::unique_ptr<std::string> uPtr; std::unique_ptr<std::string>& operator->() { return uPtr; } }; int main() { A<P> a(1); std::cout << a.n << ' ' << a.sn << ' ' // A::snも有効 << a.f() << ' ' << a.sf() << ' ' // A::sf()も有効 // << &a.f << ' ' // エラー: a.fがoperator()の左辺オペランドでない場合、不正な形式 // // << a.B << ' ' // エラー: ネストされた型は許可されていない << a.RED << ' '; // 列挙子 UPtrWrapper uPtrWrap{std::make_unique<std::string>("wrapped")}; assert(uPtrWrap->data() == uPtrWrap.operator->().operator->()->data()); }
出力:
1 2 11 4 1
E2 が非静的メンバーであり、かつ E1 の結果が similar でない型を持つオブジェクトである場合、動作は未定義です:
struct A { int i; }; struct B { int j; }; struct D : A, B {}; void f() { D d; static_cast<B&>(d).j; // OK、オブジェクト式はdのBサブオブジェクトを指定する reinterpret_cast<B&>(d).j; // 未定義動作 }
組み込みポインタ-メンバアクセス演算子
メンバへのポインタを通じたメンバアクセス演算子式は以下の形式を持ちます
lhs
.*
rhs
|
(1) | ||||||||
lhs
->*
rhs
|
(2) | ||||||||
T
の式でなければなりません。
T*
の式でなければなりません。
rhs
は、
T
のメンバへのポインタ(
data
または
function
)のrvalue、または
T
の明確でアクセス可能な基底クラス
B
のメンバへのポインタのrvalueでなければなりません。
式 E1 - > * E2 は組み込み型に対して ( * E1 ) . * E2 と完全に等価です。そのため、以下の規則では E1. * E2 のみを扱います。
式 E1. * E2 において:
- E1 が左辺値の場合、結果はそのデータメンバを指す左辺値、
- それ以外の場合( E1 が 右辺値 (C++17まで) xvalue(prvalueから 実体化 される可能性あり) (C++17以降) の場合)、結果はそのデータメンバを指す 右辺値 (C++11まで) xvalue (C++11以降) となる;
&
を持つメンバ関数を指す場合、プログラムは不適格となる
ただし、そのメンバ関数が
const
修飾子を持つが
volatile
修飾子を持たない場合は除く
(C++20以降)
;
|
7)
E1
が左辺値であり、かつ
E2
が ref-qualifier
&&
を持つメンバ関数を指す場合、プログラムは不適格となる。
|
(C++11以降) |
ユーザー定義演算子に対するオーバーロード解決
において、型
D
、
B
、
R
のすべての組み合わせについて、クラス型
B
が
D
と同じクラスであるか、または
D
の明確でアクセス可能な基底クラスであり、かつ
R
がオブジェクト型または関数型である場合、以下の関数シグネチャがオーバーロード解決に参加します:
|
R
&
operator
-
>
*
(
D
*
, R B
::
*
)
;
|
||
両方のオペランドがcv修飾されている可能性があり、その場合、戻り値の型のcv修飾はオペランドのcv修飾の和集合となります。
#include <iostream> struct S { S(int n) : mi(n) {} mutable int mi; int f(int n) { return mi + n; } }; struct D : public S { D(int n) : S(n) {} }; int main() { int S::* pmi = &S::mi; int (S::* pf)(int) = &S::f; const S s(7); // s.*pmi = 10; // error: cannot modify through mutable std::cout << s.*pmi << '\n'; D d(7); // base pointers work with derived object D* pd = &d; std::cout << (d.*pf)(7) << ' ' << (pd->*pf)(8) << '\n'; }
出力:
7 14 15
標準ライブラリ
添字演算子は多くの標準コンテナクラスによってオーバーロードされます:
|
特定のビットにアクセスする
(
std::bitset<N>
の公開メンバ関数)
|
|
|
管理対象の配列への添字アクセスを提供する
(
std::unique_ptr<T,Deleter>
の公開メンバ関数)
|
|
|
指定された文字にアクセスする
(
std::basic_string<CharT,Traits,Allocator>
の公開メンバ関数)
|
|
|
指定された要素にアクセスする
(
std::array<T,N>
の公開メンバ関数)
|
|
|
指定された要素にアクセスする
(
std::deque<T,Allocator>
の公開メンバ関数)
|
|
|
指定された要素にアクセスする
(
std::vector<T,Allocator>
の公開メンバ関数)
|
|
|
指定された要素にアクセスまたは挿入する
(
std::map<Key,T,Compare,Allocator>
の公開メンバ関数)
|
|
|
指定された要素にアクセスまたは挿入する
(
std::unordered_map<Key,T,Hash,KeyEqual,Allocator>
の公開メンバ関数)
|
|
|
インデックスによる要素へのアクセス
(
std::reverse_iterator<Iter>
の公開メンバ関数)
|
|
|
インデックスによる要素へのアクセス
(
std::move_iterator<Iter>
の公開メンバ関数)
|
|
|
valarrayの要素、スライス、またはマスクの取得/設定
(
std::valarray<T>
の公開メンバ関数)
|
|
|
指定された部分マッチを返す
(
std::match_results<BidirIt,Alloc>
の公開メンバ関数)
|
間接参照演算子とメンバー演算子は、多くのイテレータとスマートポインタクラスによってオーバーロードされます:
|
管理対象オブジェクトへのポインタを逆参照
(
std::unique_ptr<T,Deleter>
の公開メンバ関数)
|
|
|
格納されたポインタを逆参照
(
std::shared_ptr<T>
の公開メンバ関数)
|
|
|
管理対象オブジェクトにアクセス
(
std::auto_ptr<T>
の公開メンバ関数)
|
|
|
イテレータを逆参照
(
std::raw_storage_iterator<OutputIt,T>
の公開メンバ関数)
|
|
|
デクリメントされた基盤イテレータを逆参照
(
std::reverse_iterator<Iter>
の公開メンバ関数)
|
|
|
何もしない
(
std::back_insert_iterator<Container>
の公開メンバ関数)
|
|
|
何もしない
(
std::front_insert_iterator<Container>
の公開メンバ関数)
|
|
|
何もしない
(
std::insert_iterator<Container>
の公開メンバ関数)
|
|
|
指し示す要素にアクセス
(
std::move_iterator<Iter>
の公開メンバ関数)
|
|
|
現在の要素を返す
(
std::istream_iterator<T,CharT,Traits,Distance>
の公開メンバ関数)
|
|
|
何もしない
(
std::ostream_iterator<T,CharT,Traits>
の公開メンバ関数)
|
|
|
現在の文字のコピーを取得
(
std::istreambuf_iterator<CharT,Traits>
の公開メンバ関数)
|
|
|
何もしない
(
std::ostreambuf_iterator<CharT,Traits>
の公開メンバ関数)
|
|
|
現在のマッチにアクセス
(
std::regex_iterator<BidirIt,CharT,Traits>
の公開メンバ関数)
|
|
|
現在のサブマッチにアクセス
(
std::regex_token_iterator<BidirIt,CharT,Traits>
の公開メンバ関数)
|
標準ライブラリのクラスは
operator
&
をオーバーロードしません。オーバーロードされた
operator
&
の最もよく知られた例はMicrosoft COMクラスの
CComPtr
ですが、
boost.spirit
のようなEDSLでも見られます。
標準ライブラリのクラスは operator - > * をオーバーロードしていません。これは スマートポインタインターフェース の一部となり得ることが提案され、実際 boost.phoenix のアクターでその役割として使用されていますが、 cpp.react のようなEDSLでより一般的に見られます。
注記
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_multidimensional_subscript
|
202110L
|
(C++23) | 多次元添字演算子 |
不具合報告
以下の動作変更欠陥報告書は、以前に公開されたC++標準に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 1213 | C++11 | 配列右辺値の添字付け結果が左辺値となっていた | x値として再分類 |
| CWG 1458 | C++98 |
不完全クラス型の左辺値に
&
を適用した場合、
operator & を宣言していると未定義動作となっていた |
未規定となり、
どの & が使用されるかは不定 |
| CWG 1642 | C++98 | 組み込みポインタ対メンバアクセス演算子の rhs が左辺値となり得た | 右辺値のみ可能 |
| CWG 1800 | C++98 |
メンバ匿名共用体の非静的データメンバに
&
を適用する際、
匿名共用体が結果の型に含まれるか不明確であった |
匿名共用体は
結果の型に 含まれない |
| CWG 2614 | C++98 | E2 が参照メンバまたは列挙子の場合の E1. E2 の結果が不明確であった | 明確化された |
| CWG 2725 | C++98 | E2 が静的メンバ関数の場合、 E1. E2 は operator ( ) の左側オペランドでなくても適格であった | この場合 E1. E2 は不適格 |
| CWG 2748 | C++98 | E1 がヌルポインタで E2 が静的メンバを参照する場合の E1 - > E2 の動作が不明確であった |
この場合の動作は
未定義 |
| CWG 2813 | C++98 | E1. E2 が静的メンバまたは列挙を指す場合、 E1 は破棄値式ではなかった | 破棄値式となる |
| CWG 2823 | C++98 | expr がオブジェクトまたは関数を指さない場合の * expr の動作が不明確であった | 明確化された |
関連項目
| 一般的な演算子 | ||||||
|---|---|---|---|---|---|---|
| 代入 |
インクリメント
デクリメント |
算術 | 論理 | 比較 |
メンバー
アクセス |
その他 |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
...
]
|
関数呼び出し
a ( ... ) |
|
コンマ
a, b |
||||||
|
条件演算子
a ? b : c |
||||||
| 特殊な演算子 | ||||||
|
static_cast
関連する型間の変換を行う
|
||||||
|
C documentation
for
Member access operators
|