Всем привет. Имеется программа моделирующая поведение системы n-тел во времени. Соотвественно у класса модель есть 2 типа функций - моделирующие движение по времени:
void explicit_euler(T period, T time_step, !тутдолжнабытьфункция);
и считающие вектор сил:
std::vector<vector_type> quadratic(const std::vector<object_type *>& objects);
std::vector<vector_type> finit_element(const std::vector<object_type *>& objects);
А также функция запускающая процесс с нужными параметрами:
void simulate (QString state_directory_name,
T period,
T time_step,
time_method time = time_method::explicit_euler,
force_method force = force_method::quadratic);
, где
enum class time_method { explicit_euler };
enum class force_method { quadratic, finit_element };
using system_type = gravity::system<T, dim>;
using object_type = gravity::object<T, dim>;
using vector_type = geometry::vector<T, dim>;
Как правильно формировать объект std::function в зависимости от выбранного метода расчёта сил?
Пока что-то такое. Но не рабочее, судя по всему.
template<typename T, size_t dim>
void model<T, dim>::simulate (QString state_directory_name,
T period, T time_step,
time_method time,
force_method force)
{
std::function<std::vector<vector_type>(const std::vector<object_type *>&)> method;
switch(force)
{
case force_method::quadratic:
{
method = quadratic;
break;
}
case force_method::finit_element:
{
method = finit_element;
break;
}
}
switch(time)
{
case time_method::explicit_euler:
{
explicit_euler(period, time_step, method);
break;
}
}
}
Для функций
std::vector<vector_type> quadratic(const std::vector<object_type *>& objects);
std::vector<vector_type> finit_element(const std::vector<object_type *>& objects);
правильный тип std::function будет
std::function<std::vector<vector_type>(const std::vector<object_type *>&)>
Такой пример компилируется:
#include<vector>
#include<array>
#include<functional>
using vector_type = std::array<int,3>;
using object_type = vector_type;
std::vector<vector_type> quadratic(const std::vector<object_type*>& objects){
return {std::array<int,3>{1,2,3}};
}
std::vector<vector_type> finit_element(const std::vector<object_type*>& objects){
return {};
}
volatile static int v = 0;
auto foo(){
std::function<std::vector<vector_type>(const std::vector<object_type*>&)> fn;
if(v == 0)
fn = quadratic;
else
fn = finit_element;
return 0;
}
Есть подозрение, что quadratic и finit_element - это не свободные функции, а функции-члены (методы), указатель на которые - это не то, что вам нужно. Если это так, сделайте их статическими.
EDIT:
В c++ есть два типа функций: свободные функции и функции-члены. Функции-члены могут быть статическими и локальными. Статические функции эквивалентны свободным функциям, но находятся в области видимости класса, а не пространства имен.
Свободные и статические функции свободно преобразуются в указатель на функцию с соответствующей сигнатурой. Но нестатические функции-члены не могут быть напрямую преобразованы в указатель на функцию, т.к. они косвенно используют this, который им каким-то образом нужно передать. Тем не менее можно получить указатель на функцию-член, который абсолютно несовместим с обычными указателями на функцию и имеет специальный синтаксис.
std::function вносит синтаксический сахар и позволяет работать с функциями - членами так же, как и со свободными функциями, передавая первым параметром ссылку на объект класса. Реально это имеет смысл, если ваша функция использует не статические поля класса, в противном случае лучше объявить её как статическую.
Вот пример использования всех трех видов функций:
#include<vector>
#include<array>
#include<functional>
#include<iostream>
class MyInt{
int v_;
public:
MyInt(int v): v_{v} { }
// Функция - член
void setV(int v) { v_ = v; }
int getV()const {return v_;}
// Статическая функция
static int static_setV(MyInt& self, int v) {
return self.v_ = v; // Обратите внимание, есть доступ к private - полю
// Кроме того, для шаблонных типов доступны все соответствующие типы шаблона
}
};
// Свободная функция
void free_setV(MyInt& i, int v){
i.setV(v); // Нет доступа к private-полю, если не объявлена дружественной
}
int main (){
std::function<void(MyInt&, int)> set_value_fn;
MyInt i {0};
std::cout << i.getV() <<std::endl;
set_value_fn = MyInt::static_setV;
set_value_fn(i, 1);
std::cout << i.getV() <<std::endl;
set_value_fn = free_setV;
set_value_fn(i, 2);
std::cout << i.getV() <<std::endl;
set_value_fn = &MyInt::setV;
set_value_fn(i, 3);
std::cout << i.getV() <<std::endl;
return 0;
}
Проблема решилась. Ошибка была в том что функции-члены класса и свободные функции оборачиваются в std::function по разному. Тщательно проверив код и сравнив типы операндов я аккуратно написал обертку.
Функция запуска процесса по параметрам:
template<typename T, size_t dim>
void model<T, dim>::simulate (QString state_directory_name,
T period, T time_step,
time_method time,
force_method force)
{
std::function<std::vector<vector_type>(const model<T, dim>&, const std::vector<object_type *>&)> method;
switch(force)
{
case force_method::quadratic:
{
method = &model<T,dim>::quadratic;
break;
}
case force_method::finit_element:
{
method = &model<T,dim>::finit_element;
break;
}
}
switch(time)
{
case time_method::explicit_euler:
{
explicit_euler(period, time_step, method);
break;
}
}
}
Замечу, что я дополнительно указал ключевое слово const, поскольку эти функции не будут менять члены класса:
std::vector<vector_type> quadratic(const std::vector<object_type *>& objects) const;
std::vector<vector_type> finit_element(const std::vector<object_type *>& objects) const;
Если они будут менять члены класса - const надо будет убрать и у const model<T, dim>&.
Прототип функции в которую я передаю сформированный объект std::function теперь выглядит так:
void explicit_euler(T period, T time_step,
std::function<std::vector<vector_type>(const model<T, dim>&, const std::vector<object_type *>&)> method);
При инстанцировании std::function надо не забывать, что если это обёртка для шаблонной функции - параметры шаблонов должны передаваться обязательно:
Не const model&, а const model<T, dim>&, к примеру.
Также, в вызов обёрнутой функции нужно добавлять ссылку на объект, у которого функция вызывается. В моем случае так (поскольку я вызываю функцию объекта того же класса, в котором и нахожусь).
method(*this, objects);
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники