Всем привет. Имеется программа моделирующая поведение системы 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);
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Изучаю параллельное программирование (MPI)При попытке передать массив всем процессам с помощью функции MPI_Bcast, сталкиваюсь с тем, что его получает...
Можно ли объявлять классы внутри функций? А передавать созданные таким образом объекты в другие функции? Например, данный код выполняется,...
Добрый день! Никак не удаётся написать или найти программу, которая позволяла бы выводить на экран версию BIOS текущего компьютераНужен код...
Доброго дняПо заданию требуется записать в бинарник несколько массивов структур