我在阅读 cppreference 的 std::thread 文档时(我知道它并不总是百分之百正确),注意到当将“指向数据成员”的指针(而不是“指向成员函数”的指针)作为其第一个参数(f)传递给 std::thread 并将所需类的对象作为其第二个参数(复制到线程局部存储后的 t1)时,std::thread 表现的定义如下:
如果 N == 1 且 f 是指向类的成员数据对象的指针,则可以访问该成员。对象的值被忽略。实际上,执行以下代码:
- 如果 t1 的类型是 T、T 的引用或派生自 T 的类型,则执行 t1.*f。
- 否则执行 (*t1).*f。
现在,我并不打算以这种方式使用 std::thread,但是我被这个定义搞糊涂了。显然,唯一发生的事情是访问了数据成员并忽略了其值,这似乎根本没有任何可观察的副作用,也就是说(据我所知),它可能是一个无操作。(我可能错过了一些显而易见的东西……?)
一开始,我以为这可能是打印错误,并且意思是访问数据成员然后调用它(因为它可能是一个可调用对象,即使它不是一个函数),但我在GCC-4.7中使用以下代码测试了一下,确实没有调用:
这个定义似乎没有任何作用,是否可以将传递“指向数据成员可调用”的行为与“指向成员函数”的行为相同,将传递“指向数据成员不可调用”的行为视为错误?实际上,这似乎是最容易实现的方式,因为在其他上下文中调用“指向数据成员可调用”具有与调用“指向成员函数”的等效语法(除非模板特化和SFINAE规则中存在某些复杂性使它们难以等效处理...?)。我不需要实际代码,但这个定义的存在让我怀疑自己是否缺少一些基本的东西,这让我担心...有人能给我解释一下吗?
一开始,我以为这可能是打印错误,并且意思是访问数据成员然后调用它(因为它可能是一个可调用对象,即使它不是一个函数),但我在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;
}
这个定义似乎没有任何作用,是否可以将传递“指向数据成员可调用”的行为与“指向成员函数”的行为相同,将传递“指向数据成员不可调用”的行为视为错误?实际上,这似乎是最容易实现的方式,因为在其他上下文中调用“指向数据成员可调用”具有与调用“指向成员函数”的等效语法(除非模板特化和SFINAE规则中存在某些复杂性使它们难以等效处理...?)。我不需要实际代码,但这个定义的存在让我怀疑自己是否缺少一些基本的东西,这让我担心...有人能给我解释一下吗?
INVOKE
定义。有一个与您意图类似的问题,特别是针对INVOKE
定义中这个措辞的问题:https://dev59.com/02jWa4cB1Zd3GeqPv_k3。 - jogojapan