Visual C++ 14 - 无法构建基于 Visual C++ 12 的简单线程程序
Visual C++ 14 - cannot build a simple thread program which builds on Visual C++ 12
我有这个 MCVE
#include <iostream>
#include <thread>
class Foo
{
void bar_i() { std::cout << "hello" << std::endl; }
public:
void bar()
{
// I don't know why I used std::ref(*this) instead of this, I wrote this some time ago
std::thread t(&Foo::bar_i, std::ref(*this));
t.join();
}
};
int main()
{
Foo f;
f.bar();
}
基于 VS 2013 Update 3 和 Coliru,但不基于 VS 2015 并出现以下错误列表:
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: With the following template arguments:
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: '_Callable=void (__thiscall Foo::* )(void)'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: '_Types={std::reference_wrapper<Foo>}'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(247): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Execute<0,1>(std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>> &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>,
1> _Ty=size_t
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(247): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Execute<0,1>(std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>> &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>,
1> _Ty=size_t
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(242): note: while compiling class template member function 'void std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *) noexcept'
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(230): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *) noexcept' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(256): note: see reference to class template instantiation 'std::_LaunchPad<_Target>' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thread(52): note: see reference to function template instantiation 'void std::_Launch<std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>>(_Thrd_t *,_Target &&)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> d:\libraries\c++ active\tests\tests\test.cpp(13): note: see reference to function template instantiation 'std::thread::thread<void(__thiscall Foo::* )(void),std::reference_wrapper<Foo>,void>(_Fn &&,std::reference_wrapper<Foo> &&)' being compiled
1> with
1> [
1> _Fn=void (__thiscall Foo::* )(void)
1> ]
如果不是 std::ref
,此代码将编译。好像是什么问题?
据我所知,20.9.2 中的规则导致您的代码等同于
auto f = &Foo::bar_i;
decay<decltype(std::ref(*this))>::type t1 = std::ref(*this); // still reference_wrapper
((*t1).*f)();
这实际上是一个错误。
只需使用 std::thread t(&Foo::bar_i, this);
,因为 std::thread
中存在的成员函数指针机制知道在执行调用时取消引用第一个参数。
根据我正在查看的草案n4527,std::bind
(参见 20.9.10.3)使用的 std::reference_wrapper
的特殊处理不适用于 std::thread
. std::tuple
使用的特殊衰减逻辑也不是,这导致 reference_wrapper
成为正常参考。
我有这个 MCVE
#include <iostream>
#include <thread>
class Foo
{
void bar_i() { std::cout << "hello" << std::endl; }
public:
void bar()
{
// I don't know why I used std::ref(*this) instead of this, I wrote this some time ago
std::thread t(&Foo::bar_i, std::ref(*this));
t.join();
}
};
int main()
{
Foo f;
f.bar();
}
基于 VS 2013 Update 3 和 Coliru,但不基于 VS 2015 并出现以下错误列表:
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: With the following template arguments:
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: '_Callable=void (__thiscall Foo::* )(void)'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(238): note: '_Types={std::reference_wrapper<Foo>}'
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(247): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Execute<0,1>(std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>> &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>,
1> _Ty=size_t
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(247): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Execute<0,1>(std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>> &,std::integer_sequence<_Ty,0,1>)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>,
1> _Ty=size_t
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(242): note: while compiling class template member function 'void std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *) noexcept'
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(230): note: see reference to function template instantiation 'void std::_LaunchPad<_Target>::_Run(std::_LaunchPad<_Target> *) noexcept' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thr\xthread(256): note: see reference to class template instantiation 'std::_LaunchPad<_Target>' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> c:\program files (x86)\microsoft visual studio 14.0\vc\include\thread(52): note: see reference to function template instantiation 'void std::_Launch<std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>>(_Thrd_t *,_Target &&)' being compiled
1> with
1> [
1> _Target=std::unique_ptr<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>,std::default_delete<std::tuple<void (__thiscall Foo::* )(void),std::reference_wrapper<Foo>>>>
1> ]
1> d:\libraries\c++ active\tests\tests\test.cpp(13): note: see reference to function template instantiation 'std::thread::thread<void(__thiscall Foo::* )(void),std::reference_wrapper<Foo>,void>(_Fn &&,std::reference_wrapper<Foo> &&)' being compiled
1> with
1> [
1> _Fn=void (__thiscall Foo::* )(void)
1> ]
如果不是 std::ref
,此代码将编译。好像是什么问题?
据我所知,20.9.2 中的规则导致您的代码等同于
auto f = &Foo::bar_i;
decay<decltype(std::ref(*this))>::type t1 = std::ref(*this); // still reference_wrapper
((*t1).*f)();
这实际上是一个错误。
只需使用 std::thread t(&Foo::bar_i, this);
,因为 std::thread
中存在的成员函数指针机制知道在执行调用时取消引用第一个参数。
根据我正在查看的草案n4527,std::bind
(参见 20.9.10.3)使用的 std::reference_wrapper
的特殊处理不适用于 std::thread
. std::tuple
使用的特殊衰减逻辑也不是,这导致 reference_wrapper
成为正常参考。