[解決済み】「*this の rvalue 参照」とは何ですか?
質問
clangの「*this"rvalue reference」という提案に出会いました。 C++11ステータスページ .
rvalue参照についてはかなり読み込んで理解しているのですが、これについては知らないようです。また、Web上でこの用語を使ったリソースをあまり見つけることができませんでした。
ページ内に提案論文へのリンクがあります。 N2439 (Extending move semantics to *this), but I also not getting much examples from there.
この機能はどのようなものですか?
解決方法は?
まず、quot;ref-qualifiers for *this" は、単なるマーケティング・ステートメントに過ぎないのです。のタイプは
*this
は決して変わりません。この記事の一番下をご覧ください。でも、この表現の方がずっとわかりやすいですね。
次に、以下のコードでは、呼び出す関数を リファレンシャルクォリファイア の暗黙のオブジェクト・パラメータを使用します。 † :
// t.cpp
#include <iostream>
struct test{
void f() &{ std::cout << "lvalue object\n"; }
void f() &&{ std::cout << "rvalue object\n"; }
};
int main(){
test t;
t.f(); // lvalue
test().f(); // rvalue
}
出力します。
$ clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic t.cpp
$ ./a.out
lvalue object
rvalue object
全体として、関数が呼び出されたオブジェクトがrvalue(無名テンポラリなど)である場合に、その事実を利用できるようにするために行われます。さらに例として次のコードを見てみましょう。
struct test2{
std::unique_ptr<int[]> heavy_resource;
test2()
: heavy_resource(new int[500]) {}
operator std::unique_ptr<int[]>() const&{
// lvalue object, deep copy
std::unique_ptr<int[]> p(new int[500]);
for(int i=0; i < 500; ++i)
p[i] = heavy_resource[i];
return p;
}
operator std::unique_ptr<int[]>() &&{
// rvalue object
// we are garbage anyways, just move resource
return std::move(heavy_resource);
}
};
少し不自然かもしれませんが、イメージはつかめるはずです。
を組み合わせることができることに注意してください。
cv-qualifiers
(
const
と
volatile
) と
リファレンシャルクォリフィエ
(
&
と
&&
).
注:多くの標準的な引用と過負荷解消の説明はこの後にあります
この仕組みと、@Nicol Bolasの答えが少なくとも部分的には間違っている理由を理解するためには、C++標準を少し掘り下げる必要があります(@Nicolの答えが間違っている理由を説明している部分は一番下にありますので、それだけに興味がある方はご覧ください)。
どの関数が呼び出されるかは 過負荷解消 . この処理はかなり複雑なので、重要な部分だけ触ることにします。
まず、メンバ関数の過負荷解消がどのように行われるかを確認することが重要です。
§13.3.1 [over.match.funcs]
p2 候補関数のセットには、同じ引数リストに対して解決すべきメンバー関数と非メンバー関数の両方が含まれる可能性があります。そのため、引数リストとパラメータリストはこの異種集合の中で比較可能です。 メンバー関数は、暗黙のオブジェクトパラメータと呼ばれる、メンバー関数が呼び出されたオブジェクトを表す追加のパラメータを持っているとみなされます。 . [...]
p3 同様に、適切な場合には、コンテキストは、引数リストとして 暗黙のオブジェクト引数 で、操作されるオブジェクトを表す。
なぜ、メンバー関数と非メンバー関数を比較する必要があるのでしょうか?演算子のオーバーロードがその理由です。これを考えてみよう。
struct foo{
foo& operator<<(void*); // implementation unimportant
};
foo& operator<<(foo&, char const*); // implementation unimportant
確かに以下のようにfree関数を呼び出してほしいですよね。
char const* s = "free foo!\n";
foo f;
f << s;
そのため、メンバー関数と非メンバー関数は、いわゆるオーバーロードセットに含まれます。解決を複雑にしないために、標準的な引用の太字の部分が存在する。さらに、これは我々にとって重要なビットである(同条項)。
p4 非静的メンバ関数の場合、暗黙のオブジェクトパラメータの型は
「へのlvalue参照 cv
X
" なしで宣言された関数に対して リフクォリファイア または&
リフクォリファイア「へのrvalue参照 cv
X
" で宣言された関数に対して&&
リフクォリファイアどこ
X
はその関数が所属するクラスであり cv はメンバ関数宣言のcv-qualificationです。[...]p5 オーバーロードの解決中[...] [t]暗黙のオブジェクトパラメータ[...]は、対応する引数の変換がこれらの追加規則に従わなければならないので、その同一性を保持する。
暗黙のオブジェクトパラメーターの引数を保持するために、一時的なオブジェクトを導入することはできません。
この型に一致させるために、ユーザー定義の変換を適用することはできません。
[...]
(最後のビットは、メンバ関数(または演算子)が呼び出されたオブジェクトの暗黙の変換に基づいてオーバーロード解決をごまかすことができないということを意味しているだけです)。
この記事の冒頭にある最初の例を見てみましょう。前述の変換後、オーバーロードセットは次のようになります。
void f1(test&); // will only match lvalues, linked to 'void test::f() &'
void f2(test&&); // will only match rvalues, linked to 'void test::f() &&'
次に、引数リストには 暗黙のオブジェクト引数 は、オーバーロード・セットに含まれるすべての関数のパラメータ・リストと照合されます。この場合、引数リストには、そのオブジェクト引数のみが含まれます。どのように見えるか見てみましょう。
// first call to 'f' in 'main'
test t;
f1(t); // 't' (lvalue) can match 'test&' (lvalue reference)
// kept in overload-set
f2(t); // 't' not an rvalue, can't match 'test&&' (rvalue reference)
// taken out of overload-set
セット内のすべてのオーバーロードをテストした後、1つだけ残った場合、オーバーロードの解決は成功し、その変換されたオーバーロードにリンクされた関数が呼び出されます。f'の2回目の呼び出しも同様です。
// second call to 'f' in 'main'
f1(test()); // 'test()' not an lvalue, can't match 'test&' (lvalue reference)
// taken out of overload-set
f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference)
// kept in overload-set
しかし、もし
リファレンシャルクォリファイア
(そのため、この関数をオーバーロードしていない)、その
f1
となる
はrvalueにマッチします(やはり
§13.3.1
):
p5 [...] 静的でないメンバ関数が リファレンシャルクォリファイア 追加ルールが適用されます。
- 暗黙のオブジェクトパラメータが
const
-qualifiedでは、他のすべての点で引数が暗黙のオブジェクトパラメータの型に変換できる限り、パラメータにrvalueをバインドすることができます。
struct test{
void f() { std::cout << "lvalue or rvalue object\n"; }
};
int main(){
test t;
t.f(); // OK
test().f(); // OK too
}
さて、@Nicolさんの回答が少なくとも一部間違っている理由についてです。彼はこう言っています。
この宣言は
*this
.
それは間違いです。
*this
は
常に
l値である。
§5.3.1 [expr.unary.op] p1
単項演算子
*
演算子は インダイレクト : 適用される式は,オブジェクト型へのポインタ,または関数型へのポインタでなければならない。 であり、結果は lvalue である。 式が指し示すオブジェクトまたは関数を参照する。
§9.3.2 [class.this] p1
非静的(9.3)メンバ関数の本体で、キーワード
this
はprvalue式で、その値は関数が呼び出されたオブジェクトのアドレスです。の型はthis
クラスのメンバ関数でX
はX*
. [...]
関連
-
[解決済み】C++でint型に無限大を設定する
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] ルール・オブ・スリーとは?
-
[解決済み] コピーアンドスワップ慣用句とは?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
-
[解決済み】C++11のラムダ式って何?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】致命的なエラー LNK1169: ゲームプログラミングで1つ以上の多重定義されたシンボルが発見された
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】'cout'は型名ではない
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない