OpenMP с C++: внутренняя ошибка компилятора с распараллеленной лямбдой в функции шаблона

У меня есть код, который вызывает функцию шаблона, которая определяет лямбду, а затем вызывает ее. При попытке распараллелить лямбду с помощью пользовательского сокращения в 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 12.04.2023 12:07

@ 463035818_is_not_a_number Вопрос ОП касается 1) действительности их кода и 2) возможного обходного пути.

PierU 12.04.2023 13:59

@SirVivor Пожалуйста, добавьте следующие данные: 1) какой компилятор и версия; 2) командная строка, с которой вы компилируете; 3) сообщение об ошибке

PierU 12.04.2023 14:01

Код как есть компилируется и работает с компиляторами Intel, как классическими, так и основанными на llvm (по крайней мере, версия 2022.2.1+). С g++ версии 10.3.0 это не так и выдает ошибку user defined reduction not found for ‘a’. Перемещение #pragma omp declare reduction вверх непосредственно перед строкой template устраняет проблему. Здесь я бы поставил его на первое место, но IDK, если его текущее местоположение приемлемо

Gilles 12.04.2023 15:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нашел обходной путь, который сработал для моего случая, и подумал, что поделюсь им, если у кого-то возникнет аналогичная проблема (маловероятно, я знаю...):

Указание типа аргумента в лямбда-функции заставило компилятор снова понять код:

#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;
}

Другие вопросы по теме