【问题标题】:Use member function for `std::thread` with `std::ref(*this)` fails to compile使用带有 `std::ref(*this)` 的 `std::thread` 的成员函数无法编译
【发布时间】:2015-10-03 17:24:52
【问题描述】:

我使用以下最小示例来重现当我尝试创建一个调用非静态成员函数来完成其工作的线程时遇到的编译器错误:

#include <thread>
#include <iostream>
class Worker
{
public:
  Worker() : m_worker(&Worker::doWork, std::ref(*this), 1)
  {}
  std::thread m_worker;

  void doWork(int a) { std::cout << a << std::endl; }
};

int main(int argc, char* argv[]) {
  Worker k;
}

使用 gcc4.8-gcc5.1 编译失败,原因如下:

In file included from /usr/include/c++/4.8/thread:39:0,

from /tmp/gcc-explorer-compiler115614-69-rgangs/example.cpp:1:

/usr/include/c++/4.8/functional: In instantiation of 'struct std::_Bind_simple<std::_Mem_fn<void (Worker::*)(int)>(std::reference_wrapper<Worker>, int)>':

/usr/include/c++/4.8/thread:137:47: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Worker::*)(int); _Args = {std::reference_wrapper<Worker>, int}]'

7 : required from here

/usr/include/c++/4.8/functional:1697:61: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Worker::*)(int)>(std::reference_wrapper<Worker>, int)>'

typedef typename result_of<_Callable(_Args...)>::type result_type;

^

/usr/include/c++/4.8/functional:1727:9: error: no type named 'type' in 'class std::result_of<std::_Mem_fn<void (Worker::*)(int)>(std::reference_wrapper<Worker>, int)>'

_M_invoke(_Index_tuple<_Indices...>)

^

Compilation failed

另一方面,Clang 似乎可以很好地编译这段代码。谁是正确的,这是 gcc 中的一个错误(有开放票吗?)?


编辑: 当使用m_worker(&amp;Worker::doWork, this, 1) 初始化线程时,gcc 编译它就好了。那么,在这种情况下使用std::ref(*this) 是否合法?我猜任何std::ref(),更笼统。

【问题讨论】:

标签: c++ gcc c++14 standards-compliance


【解决方案1】:

您的 thread 构造函数调用依赖于以下语义:

[C++14: 30.3.1.2/3]: 要求: FArgs 中的每个Ti 应满足MoveConstructible 要求。 INVOKE (DECAY_COPY ( std::forward&lt;F&gt;(f)), DECAY_COPY (std::forward&lt;Args&gt;(args))...) (20.9.2) 应该是一个有效的表达式。

INVOKE 是这样定义的:

[C++14: 20.9.2/1]: 定义 INVOKE (f, t1, t2, ..., tN) 如下:

  • (t1.*f)(t2, ..., tN)f 是指向类T 的成员函数的指针并且t1T 类型的对象或对T 类型对象的引用或对T 类型对象的引用时派生自T 的类型;
  • ((*t1).*f)(t2, ..., tN)f 是指向T 类的成员函数的指针且t1 不是上一项中描述的类型之一时;
  • t1.*fN == 1f 是指向类的成员数据的指针 Tt1T 类型的对象或对 T 类型对象的引用或对派生自T 的类型的对象;
  • (*t1).*fN == 1f 是类成员数据的指针Tt1 不是上一项中描述的类型之一;
  • f(t1, t2, ..., tN) 在所有其他情况下。

如您所见,这里没有为std::reference_wrapper&lt;Worker&gt; 提供任何规定,这是std::ref(*this) 为您提供的。当然,衰减规则中没有任何帮助 ([C++14: 30.2.6/1])。

Clang 实际上在这里有点过激,似乎允许这样做,因为由于我们自己的 Jonathan Wakely 归档 Library Working Group issue #2219 有一天它会符合标准。但是,目前还不是。

无论如何,这整件事都没有实际意义。无需编写此代码。就这样写吧:

Worker() : m_worker(&Worker::doWork, this, 1)

【讨论】:

  • 是的 ref() 用于参数,而不是可调用的。鉴于您始终可以随时获取可调用的指针,无论如何您都可以获取引用,因此过度复杂化语言以允许此类事情可能没有意义。
  • ^ 基本上也是我的想法
  • 哈,看 Praetorian 的 comment 猜猜它会进去。
  • @Barry:王牌!已经合并了。
猜你喜欢
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-11
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多