如何将带Lambda完成函数的std::barrier传入C++命名函数
问题:带自定义完成函数的std::barrier传入命名工作函数时编译失败
我在为密集型信号处理任务编写工作线程,采用C++20的std::jthread(优先于std::thread)。当尝试将带自定义Lambda完成函数的std::barrier传入std::jthread调用的命名工作函数时,出现编译错误;但传入无完成函数的std::barrier,或直接在线程中使用Lambda闭包则可正常编译运行。
问题复现代码
main函数代码
#include <thread> #include <barrier> int main() { std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); std::array<std::jthread> threads{}; // 注意:此处std::array未指定大小,本身存在编译问题 for (auto& thread : threads) thread = std::jthread(worker, std::ref(barrier)); return 0; }
工作函数代码
#include <thread> #include <barrier> #include <iostream> void worker(std::stop_token stopToken, std::barrier<void(void)>& barrier) noexcept { while (!stopToken.stop_requested()) { barrier.arrive_and_wait(); } std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n'; barrier.arrive_and_drop(); }
编译报错信息
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\barrier(76,13): error C2338: static_assert 失败: 'N4861 [thread.barrier.class]/5: is_nothrow_invocable_v<CompletionFunction&> shall be true' 1>C:\Users\Aris\Documents\Development\Perception Neuron\DSP\TestBarrier.cpp(27,16): 消息: 查看对类模板实例化“std::barrier<void (void)>”的引用 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\xmemory(1395,1): error C2207: 'std::_Compressed_pair<_Ty1,_Ty2,false>::_Myval1': 类模板的成员不能获取函数类型 1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\barrier(186,44): 消息: 查看对类模板实例化“std::_Compressed_pair<_Completion_function,std::barrier<_Completion_function>::_Counter_t,false>”的引用 with [ _Completion_function=void (void) ]
可行代码示例(Lambda闭包版本)
#include <thread> #include <barrier> #include <iostream> #include <array> int main() { std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); std::array<std::jthread, 4> threads{}; for (auto& thread : threads) thread = std::jthread([&barrier] (std::stop_token stopToken) { while (!stopToken.stop_requested()) { barrier.arrive_and_wait(); } std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n'; barrier.arrive_and_drop(); }); return 0; }
解决方案与原理说明
解决方案
方案1:使用auto推导barrier类型(C++20及以上支持)
修改工作函数的参数类型,让编译器自动推导std::barrier的真实类型:
#include <thread> #include <barrier> #include <iostream> #include <array> void worker(std::stop_token stopToken, auto& barrier) noexcept { while (!stopToken.stop_requested()) { barrier.arrive_and_wait(); } std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n'; barrier.arrive_and_drop(); } int main() { std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); std::array<std::jthread, 4> threads{}; // 4个工作线程+主线程,匹配barrier计数5 for (auto& thread : threads) thread = std::jthread(worker, std::ref(barrier)); return 0; }
方案2:显式指定barrier的类型别名
先通过decltype推导barrier的真实类型,再在工作函数中使用:
#include <thread> #include <barrier> #include <iostream> #include <array> // 推导barrier的真实类型 using BarrierType = decltype(std::barrier(5, []() noexcept {std::cout << "Completion reached\n\n";})); void worker(std::stop_token stopToken, BarrierType& barrier) noexcept { while (!stopToken.stop_requested()) { barrier.arrive_and_wait(); } std::cout << "Termination requested for thread " << std::this_thread::get_id() << '\n'; barrier.arrive_and_drop(); } int main() { std::barrier barrier(5, []() noexcept {std::cout << "Completion reached\n\n";}); std::array<std::jthread, 4> threads{}; for (auto& thread : threads) thread = std::jthread(worker, std::ref(barrier)); return 0; }
原理说明
std::barrier模板参数的本质:std::barrier是模板类,其模板参数是完成函数的具体类型,而非函数签名。Lambda拥有匿名的独特类型,和void(void)这种普通函数类型完全不匹配。工作函数中错误指定std::barrier<void(void)>&,导致编译器实例化了错误的模板版本,触发类型不兼容问题。报错原因拆解:
- 第一个
static_assert错误:编译器尝试实例化以void(void)为完成函数类型的std::barrier,但该类型无法满足noexcept可调用的要求,触发标准规定的静态断言检查失败。 - 第二个类成员类型错误:
std::barrier内部用std::_Compressed_pair存储完成函数,而纯函数类型不能作为类成员存储(仅支持函数指针或可调用对象),导致编译失败。
- 第一个
Lambda闭包版本可行的原因:
闭包通过引用直接捕获了原始的std::barrier对象,编译器可以自动推导其真实类型,无需手动指定,因此不会出现类型不匹配的问题。
内容的提问来源于stack exchange,提问作者user9118496
相关产品推荐
相关产品推荐

