std::bind
を使用してメンバー関数をバインドする場合、最初の引数はオブジェクトthis
ポインターです。ただし、オブジェクトをポインタとして渡す場合と渡さない場合の両方で機能します。
たとえば、次のプログラムを参照してください。
#include <iostream>
#include <functional>
struct foo
{
void bar(int v) { std::cout << "foo::bar - " << v << '\n'; }
};
int main()
{
foo my_foo;
auto f1 = std::bind(&foo::bar, my_foo, 1);
auto f2 = std::bind(&foo::bar, &my_foo, 2);
f1();
f2();
}
ClangとGCCはどちらもこれを文句なしにコンパイルし、結果は両方のバインドで機能します。
foo :: bar-1 foo :: bar-2
私は仕様(セクション20.8.9)に頭を包み込もうとしてきましたが、それは私にははっきりとは程遠い場所の1つです。
正しいのは1つだけですか、両方とも正しいですか?
両方とも正しいです。 20.8.9.1.2から20.8.2に転送して、bind
への呼び出しの要件と効果を説明します。 20.8.2は:
20.8.2要件[func.require]
1 [〜#〜] invoke [〜#〜]
(f, t1, t2, ..., tN)
を次のように定義します。—
(t1.*f)(t2, ..., tN)
がf
がクラスT
のメンバー関数へのポインターであり、t1
がT
型のオブジェクトまたはT
型のオブジェクトへの参照の場合T
から派生した型のオブジェクトへの参照。—
((*t1).*f)(t2, ..., tN)
がf
がクラスT
のメンバー関数へのポインターであり、t1
が前の項目で説明したタイプのいずれでもない場合。—
t1.*f
およびN == 1
およびf
がクラスT
のメンバーデータへのポインターであり、t1
がT
型のオブジェクトまたはT
型のオブジェクトへの参照の場合T
から派生した型のオブジェクトへの参照。—
(*t1).*f
とN == 1
およびf
がクラスT
のメンバーデータへのポインターであり、t1
が前の項目で説明したタイプのいずれでもない場合。—
f(t1, t2, ..., tN)
その他のすべての場合。
最初の2つのオプションは、参照とポインターの両方を許可します。
ここで注意すべき重要なことは、言葉遣いがnotを使用してプレーンポインターに制限することです。 std::shared_ptr
または他のスマートポインターを使用して、バインドされている間インスタンスを存続させ、std::bind
が間接参照されるため、それが何であれ(もちろん可能です)、それは引き続きt1
で動作します。
正解に追加する(両方のフォームが許可される)。
関数引数宣言と同様の2つのバインディングオプションを考えます。これは、「値によって渡される」または「参照によって渡される」可能性があります。
の場合 f1
(別名my_foo
「値による」)結果は、my_foo
結合点を通過します。これは、特にmy_foo
進化します。 「値による」バインディングには、コピーコンストラクターへの(複数の)呼び出しの追加の「コスト」があります。