У меня есть код, который вызывает функцию шаблона, которая определяет лямбду, а затем вызывает ее. При попытке распараллелить лямбду с помощью пользовательского сокращения в OpenMP я получаю внутреннюю ошибку компилятора. Я использую gcc (gcc (GCC) 12.2.1 20230201) внутри оболочки zsh.
Вот 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 не принимает аргументов.
Вопрос: Я знаю, что это ошибка компилятора, о которой следует сообщить, и я это сделаю (редактировать: Я сделал). Но вызвана ли ошибка тем, что я написал плохой код?
Если нет, есть ли способ сохранить ту же структуру кода, но заставить компилятор понять меня? Мне нужно иметь структуру основного вызова функции шаблона, вызывающую параллельную лямбду.
Спасибо за любую помощь!
@ 463035818_is_not_a_number Вопрос ОП касается 1) действительности их кода и 2) возможного обходного пути.
@SirVivor Пожалуйста, добавьте следующие данные: 1) какой компилятор и версия; 2) командная строка, с которой вы компилируете; 3) сообщение об ошибке
Код как есть компилируется и работает с компиляторами Intel, как классическими, так и основанными на llvm (по крайней мере, версия 2022.2.1+). С g++ версии 10.3.0 это не так и выдает ошибку user defined reduction not found for ‘a’
. Перемещение #pragma omp declare reduction
вверх непосредственно перед строкой template
устраняет проблему. Здесь я бы поставил его на первое место, но IDK, если его текущее местоположение приемлемо
Нашел обходной путь, который сработал для моего случая, и подумал, что поделюсь им, если у кого-то возникнет аналогичная проблема (маловероятно, я знаю...):
Указание типа аргумента в лямбда-функции заставило компилятор снова понять код:
#include <iostream>
template <class T>
T add(std::size_t const &maxs) {
auto step = [&](std::size_t 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;
}
независимо от того, какой код вы пишете, внутренняя ошибка компилятора всегда является внутренней ошибкой компилятора.