Есть ли способ создать массив функций внутри цикла в С++?

Я использую ROOT Cern для решения нелинейной системы уравнений с несколькими переменными. Для некоторых задач у меня есть 4 функции и 4 переменные. Однако для других мне нужно 20 функций с 20 переменными. Я использую класс под названием «WrappedParamFunction» для обертывания функций, а затем добавляю обернутые функции в «GSLMultiRootFinder», чтобы решить их. Функция обернута следующим образом:

ROOT::Math::WrappedParamFunction<> g0(&f0, "number of variables", "number of parameters");

Поэтому мне нужно объявить функции f0...fi перед моей void main(){} частью кода. Я объявляю функции таким образом:

double f0(const double *x, const double *par){return -par[0]+y[0]*par[1];}
double f1(const double *x, const double *par){return -par[1]+y[1]*par[2];}
.
.

Есть ли способ создать эти функции внутри цикла и сложить их в массив? Что-то вроде этого:

double (*f[20])(const double *x, const double *par);
for(int i=0;i<20;i++){
   f[i]= -par[i]+x[i]*par[i+1];
}

Чтобы позже я мог обернуть функции таким образом:

ROOT::Math::WrappedParamFunction<> g0(f[0], "number of variables", "number of parameters");

Вы знакомы с лямбда-функциями? WrappedParamFunction похоже, что он может содержать лямбду

alter_igel 26.08.2022 17:30

Вы можете создать массив указатели функций перед циклом. Главное предостережение в том, что функции должны иметь одинаковую сигнатуру.

Thomas Matthews 26.08.2022 17:32

Другой вариант — использовать оператор switch или std::map с указателями на функции. Вы также можете использовать функциональные объекты.

Thomas Matthews 26.08.2022 17:33
wandbox.org/permlink/S3sBz33LmrFNKWRz
Ryan Haining 26.08.2022 17:43

Я не согласен с дубликатом. Похоже, что OP пытается заполнить 20 различных функторов в цикле, где тело зависит от индекса цикла. Это явно вариант использования для лямбда-выражений, а не для разъяснения синтаксиса массива функций.

alter_igel 26.08.2022 17:47

Вопрос не в создании массива указателей на функции. Основная проблема заключается в процедурной генерации этих функций. И при таком использовании WrappedParamFunction это должен быть указатель на функцию (поэтому захват лямбда или std::bind невозможен)

Yksisarvinen 26.08.2022 17:47
Получение данных из формы с помощью JavaScript - краткое руководство
Получение данных из формы с помощью JavaScript - краткое руководство
Получить данные из формы с помощью JS очень просто: вы запрашиваете элемент формы, передаете его конструктору new FormData() и, наконец, получаете...
Пользовательские правила валидации в Laravel
Пользовательские правила валидации в Laravel
Если вы хотите создать свое собственное правило валидации, Laravel предоставляет возможность сделать это. Создайте правило с помощью следующей...
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
1
6
137
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

"Есть ли способ создать массив функций внутри цикла в C или C++"

Конечно, вы можете создать std::array или std::vector из std::function.

Вы также можете создать контейнер указателей на функции, если хотите.

   f[i]= -par[i]+x[i]*par[i+1];

Вы не можете генерировать код во время выполнения, поэтому вы не можете сделать в яблочко то, что вы просите.

Однако вы можете сохранить значение i для использования во время выполнения, чтобы у вас был единственный вызываемый объект со скрытым параметром i, который не передается явно вызывающей стороной. Самый простой пример

auto f = [i](const double *x, const double *par)
         {
            return -par[i]+x[i]*par[i+1];
         };

но это дает уникальный тип лямбда f, поэтому вы не можете легко получить их массив.

Однако вы можете написать

using Callable = std::function<double, const double *, const double *>;
std::array<Callable, 20> f;

и сохраните в нем лямбда-выражения.

Я думаю, вам нужно будет использовать ROOT::Math::WrappedParamFunction<Callable>, чтобы это работало, поскольку тип параметра FuncPtr не стирается.


Если вы действительно не мочь измените параметр типа WrappedParamFunction по какой-либо причине, вы можете сгенерировать бесплатную функцию вместо лямбды с отслеживанием состояния, используя шаблоны, но это довольно уродливо.

Редактировать - я тоже думал написать эту версию, но Фабиан опередил меня. Обратите внимание, что вам нужно либо написать весь этот механизм для каждой отдельной функции, которая нуждается в такой обработке, обернуть ее в макрос, либо обобщить все, чтобы также принять параметр шаблона функции.

Почти наверняка есть лучшие способы сделать это, но это, вероятно, приблизит вас к желаемому результату, описанному в вопросе:

Создайте шаблон функции со смещением в качестве параметра шаблона, а затем создайте std::array указателей на функции с указателями на функции, указывающими на специализации функции шаблона. Обратите внимание, что размер массива должен быть постоянной времени компиляции, чтобы это работало:

template<size_t Offset>
double f(const double* y, const double* par)
{
    return -par[Offset] + y[Offset] * par[Offset+1];
}

template<size_t ... Offsets>
std::array<double(*)(double const*, double const*), sizeof...(Offsets)> CreateFsHelper(std::index_sequence<Offsets...>)
{
    return { &f<Offsets>... };
}

template<size_t N>
std::array<double(*)(double const*, double const*), N> CreateFs()
{
    return CreateFsHelper(std::make_index_sequence<N>{});
}

int main()
{
    auto functions = CreateFs<20>();
}
Ответ принят как подходящий

Сделать ваш i параметром шаблона и рекурсивно генерировать функции во время компиляции также может помочь:

using FunctionPrototype = double(*)(const double *, const double *);

template<int i>
double func(const double * x, const double * par) {
  return -par[i]+x[i]*par[i+1];
}

template<int i>
void generate_rec(FunctionPrototype f[]) {
  f[i-1] = &func<i-1>;
  generate_rec<i-1>(f);
}

template<>
void generate_rec<0>(FunctionPrototype f[]) { }

template<int i>
FunctionPrototype* generate_functions()
{
  FunctionPrototype * f = new FunctionPrototype[i]();
  generate_rec<i>(f);
  return f;
}


FunctionPrototype * myFuncs = generate_functions<3>(); // myFuncs is now an array of 3 functions

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