私はcppreferenceでstd::threadのドキュメントを読んでいて(常に100%正確であるとは限りません)std::thread
、「pointer-to-data-member」(「pointer-to-」ではない)が渡されたときの動作に関する次の定義に気づきました。 member-function ")を最初の引数(f
)として、必要なクラスのオブジェクトを2番目の引数として(t1
thread-local-storageにコピーした後):
N == 1で、fがクラスのメンバーデータオブジェクトへのポインタである場合、そのオブジェクトにアクセスします。オブジェクトの値は無視されます。事実上、次のコードが実行されます。t1。* fの場合、t1のタイプはT、Tへの参照、またはTから派生したタイプへの参照(* t1)。*fのいずれかです。
今、私はこのように使用するつもりはありませんstd::thread
が、私はこの定義に混乱しています。どうやら、発生する唯一のことは、データメンバーがアクセスされ、値が無視されることです。これは、観察可能な副作用をまったく持たないようです。つまり、(私が知る限り)それはノーオペレーション。(私は明らかな何かを見逃しているかもしれません...?)
最初は、これはミスプリントである可能性があり、データメンバーにアクセスしてから呼び出されることを意味していました(関数でなくても呼び出し可能なオブジェクトである可能性があるため)が、GCCで次のコードを使用してテストしました-4.7そして実際に呼び出しはありません:
#include <iostream>
#include <thread>
struct S
{
void f() {
std::cout << "Calling f()" << std::endl;
}
struct {
void operator()() {
std::cout << "Calling g()" << std::endl;
}
} g;
};
int main(int, char**)
{
S s;
s.f(); // prints "Calling f()"
s.g(); // prints "Calling g()"
std::cout << "----" << std::endl;
auto x = &S::f; // ptr-to-mem-func
auto y = &S::g; // ptr-to-data-mem
(s.*x)(); // prints "Calling f()"
(s.*y)(); // prints "Calling g()"
std::cout << "----" << std::endl;
std::thread t(x, &s);
t.join();
// "Calling f()" printed by now
std::thread u(y, &s);
u.join();
// "Calling g()" not printed
return 0;
}
何も達成していないように見えるこの定義の目的はありますか?代わりに、「pointer-to-data-member-callable」の受け渡しを「pointer-to-member-function」のように動作させ、「pointer-to-data-member-noncallable」の受け渡しをエラーにしないのはなぜですか?実際、「pointer-to-data-member-callable」を呼び出すことは、他のコンテキストで「pointer-to-member-function」として呼び出すことと同等の構文を持っているため、これが実装する最も簡単な方法のようです(テンプレートの特殊化とSFINAEルールの迷信に、それらを同等に扱うことを困難にする何かがない限り...?)
これは実際のコードに必要なものではありませんが、この定義が存在するという事実は、私が基本的な何かを見逃しているのではないかと疑っています。