OpenMP与C++:模板函数中并行化Lambda引发内部编译器错误
问题描述
我编写了一段调用模板函数的代码,该函数定义并调用Lambda。尝试用OpenMP自定义归约并行化这个Lambda时,触发了内部编译器错误。我使用的是zsh shell下的gcc(版本12.2.1 20230201)。
最小可复现示例(MWE)
#include <iostream> template <class T> T add(std::size_t const &maxs) { auto step = [&](auto const &maxs) { T a = T(0); #pragma omp declare reduction(MyRed:T \ : omp_out += omp_in) \ initializer(omp_priv(omp_orig)) #pragma omp parallel for schedule(dynamic, 10) reduction(MyRed : a) for (std::size_t s = 0; s <= maxs; ++s) { a += T(1); } return a; }; return step(maxs); } int main() { auto a = add<double>(100); std::cout << "a=" << a << std::endl; }
编译器在第6行报错:#pragma omp declare reduction(MyRed:double。
已知当add()不是模板函数、OpenMP指令不在Lambda中,或是Lambda没有参数时,编译可以正常通过。
我的疑问:
我认为这是编译器Bug并已上报,但想确认错误是否由我的代码问题导致?如果不是,有没有办法保留现有代码结构(main调用模板函数、模板函数调用并行化Lambda)并让编译器正确处理?
回答
1. 代码本身无问题
你的代码符合C++和OpenMP的语法规范,这个内部编译器错误确实是GCC的Bug导致的,和你的代码写法无关。
2. 保留现有结构的解决方案
可以通过以下两种方式绕过这个Bug,同时保留你需要的代码结构:
方案一:将自定义归约移到Lambda外部
把#pragma omp declare reduction移到模板函数add内部、Lambda定义之前,这样编译器能正确识别模板参数T:
#include <iostream> template <class T> T add(std::size_t const &maxs) { #pragma omp declare reduction(MyRed:T \ : omp_out += omp_in) \ initializer(omp_priv(omp_orig)) auto step = [&](auto const &maxs) { T a = T(0); #pragma omp parallel for schedule(dynamic, 10) reduction(MyRed : a) for (std::size_t s = 0; s <= maxs; ++s) { a += T(1); } return a; }; return step(maxs); } int main() { auto a = add<double>(100); std::cout << "a=" << a << std::endl; }
方案二:使用OpenMP内置归约(如果适用)
如果你的归约操作是简单的加法,可以直接用OpenMP内置的+归约,省去自定义归约的步骤,这样也能避开Bug:
#include <iostream> template <class T> T add(std::size_t const &maxs) { auto step = [&](auto const &maxs) { T a = T(0); #pragma omp parallel for schedule(dynamic, 10) reduction(+: a) for (std::size_t s = 0; s <= maxs; ++s) { a += T(1); } return a; }; return step(maxs); } int main() { auto a = add<double>(100); std::cout << "a=" << a << std::endl; }
内容的提问来源于stack exchange,提问作者SirVivor
相关产品推荐
相关产品推荐

