为何为接收std::string引用的talk函数创建std::thread会编译报错?
std::thread传递左值引用参数编译失败问题解决
我写了一个talk函数,能逐字符延迟输出传入的字符串,单独调用完全正常,但用std::thread创建线程执行时出现大量编译错误。而无参数的hi函数创建线程却能正常运行。
talk函数代码
void talk(std::string& string) { for (volatile int i{0}; i < string.length(); ++i) { if (string[i] != '\n') { if (i > 0 && string[i - 1] == '\n') std::cout << '\n'; std::cout << string[i] << std::flush; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else std::this_thread::sleep_for(std::chrono::milliseconds(200)); } std::this_thread::sleep_for(std::chrono::milliseconds(300)); }
无法编译的完整代码
#include <iostream> #include <thread> #include <chrono> void talk(std::string& string) { for (volatile int i{0}; i < string.length(); ++i) { if (string[i] != '\n') { if (i > 0 && string[i - 1] == '\n') std::cout << '\n'; std::cout << string[i] << std::flush; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else std::this_thread::sleep_for(std::chrono::milliseconds(200)); } std::this_thread::sleep_for(std::chrono::milliseconds(300)); } int main() { std::string message{"Hello, how are you doing?"}; std::thread talkThread{talk, message}; talkThread.join(); return 0; }
正常运行的无参数函数代码
#include <iostream> #include <thread> void hi() { std::cout << "Hi."; } int main() { std::thread hiThread{hi}; hiThread.join(); return 0; }
编译报错信息
In file included from /usr/include/c++/11/thread:43, from main.cpp:2: /usr/include/c++/11/bits/std_thread.h: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(std::__cxx11::basic_string<char>&); _Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}; <template-parameter-1-3> = void]’: main.cpp:27:41: required from here /usr/include/c++/11/bits/std_thread.h:130:72: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues 130 | typename decay<_Args>::type...>::value, | ^~~~~ /usr/include/c++/11/bits/std_thread.h:130:72: note: ‘std::integral_constant::value’ evaluates to false /usr/include/c++/11/bits/std_thread.h: In instantiation of ‘struct std::thread::_Invoker<std::tuple<void (*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >’: /usr/include/c++/11/bits/std_thread.h:203:13: required from ‘struct std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&), std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >’: /usr/include/c++/11/bits/std_thread.h:143:29: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(std::__cxx11::basic_string<char>&); _Args = {std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&}; <template-parameter-1-3> = void]’: main.cpp:27:41: required from here /usr/include/c++/11/bits/std_thread.h:258:11: error: no type named ‘type’ in ‘struct std::thread::_Invoker, std::allocator >&), std::__cxx11::basic_string, std::allocator > > >::__result, std::allocator >&), std::__cxx11::basic_string, std::allocator > > >’ 258 | _M_invoke(_Index_tuple<_Ind...>) | ^~~~~~~~~ /usr/include/c++/11/bits/std_thread.h:262:9: error: no type named ‘type’ in ‘struct std::thread::_Invoker, std::allocator >&), std::__cxx11::basic_string, std::allocator > > >::__result, std::allocator >&), std::__cxx11::basic_string, std::allocator > > >’ 262 | operator()() | ^~~~~~~~
错误原因
核心问题在于std::thread的构造函数会对传入的参数执行类型衰减(decay),也就是把左值转换成右值。而talk函数的参数是std::string&(非const左值引用),无法绑定到衰减后的右值std::string,导致编译器认为参数无法被调用,触发静态断言失败。
解决方案
方案1:用std::ref传递引用
在创建线程时,用std::ref包裹参数,让std::thread内部保持对原变量的引用:
int main() { std::string message{"Hello, how are you doing?"}; std::thread talkThread{talk, std::ref(message)}; talkThread.join(); return 0; }
方案2:修改函数参数为const引用
因为talk函数只是读取字符串,没有修改操作,所以可以把参数改成const std::string&,这样既可以接受左值,也能兼容std::thread的参数衰减:
void talk(const std::string& string) { // 函数内容不变 } // main函数无需修改,直接传message即可 int main() { std::string message{"Hello, how are you doing?"}; std::thread talkThread{talk, message}; talkThread.join(); return 0; }
方案3:传递指针
如果确实需要非const引用(比如函数要修改字符串),也可以传递指针,避免引用绑定问题:
void talk(std::string* string) { if (!string) return; // 空指针检查 for (volatile int i{0}; i < string->length(); ++i) { if ((*string)[i] != '\n') { if (i > 0 && (*string)[i - 1] == '\n') std::cout << '\n'; std::cout << (*string)[i] << std::flush; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } else std::this_thread::sleep_for(std::chrono::milliseconds(200)); } std::this_thread::sleep_for(std::chrono::milliseconds(300)); } int main() { std::string message{"Hello, how are you doing?"}; std::thread talkThread{talk, &message}; talkThread.join(); return 0; }
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

