Идея состоит в том, чтобы вызывать аналогичные шаблоны функций Рунге-Кутта в цикле, а не делать это один за другим. Я смотрел аналогичный решения, я также пробовал void*, но не смог применить к моей проблеме из-за ошибок преобразования.
Обновлено: эти шаблоны функций предполагается использовать с типами фиксированный, это перебор, но я хотел бы посмотреть, есть ли элегантное решение.
Вот полный код:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <functional>
template <typename X, typename F, typename H = double>
X runge_kutta1(const X &x, const F &f, H h)
{
return x + h * f(x);
}
template <typename X, typename F, typename H = double>
X runge_kutta2(const X &x, const F &f, H h)
{
X k1 = f(x);
return x + 0.5 * h * (k1 + f(x + h * k1));
}
struct pair
{
double v;
double w;
pair(double v, double w)
: v{v}, w{w}
{
}
};
inline pair operator*(double h, pair p)
{
return {h * p.v, h * p.w};
}
inline pair operator+(pair p1, pair p2)
{
return {p1.v + p2.v, p1.w + p2.w};
}
inline std::ostream &operator<<(std::ostream &stream, const pair &p)
{
stream << p.v << ", " << p.w;
return stream;
}
int main() {
{
double x = 0.0;
double x1 = 1.0;
double lambda = 2;
double h = 1.0E-3;
pair p{1.0 / lambda, 0.0};
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
while (x + h < x1)
{
p = runge_kutta1(p, cat, h);
x = x + h;
}
p = runge_kutta1(p, cat, x1 - x);
pair expected = {cosh(lambda * x1) / lambda, sinh(lambda * x1)};
pair error = p + -1.0 * expected;
std::cout << std::setprecision(18) << "runge_kutta1:\nFinal result: " << p << "\n";
std::cout << "Error: " << error << "\n\n";
}
{
double x = 0.0;
double x1 = 1.0;
double lambda = 2;
double h = 1.0E-3;
pair p{1.0 / lambda, 0.0};
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
while (x + h < x1)
{
p = runge_kutta2(p, cat, h);
x = x + h;
}
p = runge_kutta2(p, cat, x1 - x);
pair expected = {cosh(lambda * x1) / lambda, sinh(lambda * x1)};
pair error = p + -1.0 * expected;
std::cout << "runge_kutta2:\nFinal result: " << p << "\n";
std::cout << "Error: " << error << "\n";
}
}
Что бы я хотел иметь (реальный алгоритм упрощен для удобства чтения):
std::vector<?> functions{runge_kutta1, runge_kutta2}; // two just as an example
double p = 1.0;
double h = 1.0E-3;
double lambda = 2;
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
for (const auto& func : functions) {
double t = func(p, cat, h);
std::cout << t << "\n";
}
@ Yakk-AdamNevraumont Я бы сказал, что шаблон - это не тип, а не значение - на мой взгляд, это делает его более понятным. int не имеет значения, но векторы int существуют.
@ Yakk-AdamNevraumont, я понял, есть ли способ каким-то образом создать экземпляр шаблона и использовать его внутри std :: vector? По крайней мере, в этой задаче, где все экземпляры будут иметь одинаковые типы.
И, честно говоря, о Рунге-Кутте упоминать вообще не приходится. Ваша цель - вызвать набор шаблонных функций неким контейнерным способом. Не нужно показывать нам математические расчеты, чтобы просто заявить об этом.
@MikhailKrassavin, конечно, но он будет указывать на его конкретную версию. Он будет работать только с указанными типами аргументов.
Есть целая куча вещей, которые можно сделать. Например, если у вас есть список скалярных типов, которые вы хотите поддерживать, вы можете сохранить версию указанных функций со стиранием типов. Для эффективности, если вы вызывали это в буфере значений, вы могли бы применить стирание типа к буферу. Чтобы определить, что требуется, необходимо на самом деле описать вашу реальную проблему, а не неудачное решение, которое, по вашему мнению, более чем достаточно для решения неопределенной проблемы, которой у нас нет.
Это известно как проблема X / Y. У вас есть проблема Y. Вы придумываете решение: «Если я могу решить X, я могу решить Y». Затем вы сталкиваетесь с проблемами при решении X (возможно, потому, что это невозможно) и спрашиваете о X. В этом случае ваш X, вероятно, смехотворно сильнее, чем то, что вам нужно для решения Y. Представьте, что вы хотите убить паука. Вы слышите о делении атома и думаете, что паук умрет, если вы взорвете ядерную бомбу. Пытаясь собрать ядерную бомбу, вы сталкиваетесь с проблемами при запуске центрифуг, потому что для мощности у вас есть велосипед. Итак, вы спрашиваете, как запустить урановую центрифугу на велосипеде.
Это вопрос: «Как запустить урановую центрифугу на велосипеде». И это правда, если бы вы решили эту проблему, паук действительно был бы мертв. Но эту проблему нельзя решить; так что, пожалуйста, расскажите нам о пауке, которого вы хотите убить. И не говорите: «Есть много миллиардов атомов, расположенных определенным образом, мне нужно рандомизировать». Расскажите нам как можно лучше, что такое паук.
@ Yakk-AdamNevraumont, я понимаю, что использовать такой подход до некоторой степени нелепо (конечно, простая функция с фиксированными аргументами будет работать нормально), но мне просто интересно узнать что-то новое.





У вас не может быть указателя на шаблон функции. У вас может быть только указатель на конкретный экземпляр шаблона. Точно так же вы не можете упаковать шаблон в std::function - только его конкретный экземпляр.
И вы можете помещать в контейнер только объекты одного типа, поэтому ваши указатели должны быть одного типа (т.е. функция, на которую они указывают, должна принимать аргументы одного типа и возвращать один и тот же тип).
std::function будет иметь такое же ограничение - все std::functions внутри контейнера должны быть одного типа с точки зрения возвращаемого значения и аргументов.
Шаблоны - это не ценности. Итак, ваше решение - неправильный путь, он никуда не ведет. Вам нужно создать резервную копию и переосмыслить проблему, а не пытаться решить ее с помощью «вектора шаблонов». Векторы хранят значения, шаблоны не являются значениями.