C++: std :: vector указателей шаблонов функций

Идея состоит в том, чтобы вызывать аналогичные шаблоны функций Рунге-Кутта в цикле, а не делать это один за другим. Я смотрел аналогичный решения, я также пробовал 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 - Adam Nevraumont 16.11.2018 19:58

@ Yakk-AdamNevraumont Я бы сказал, что шаблон - это не тип, а не значение - на мой взгляд, это делает его более понятным. int не имеет значения, но векторы int существуют.

SergeyA 16.11.2018 20:00

@ Yakk-AdamNevraumont, я понял, есть ли способ каким-то образом создать экземпляр шаблона и использовать его внутри std :: vector? По крайней мере, в этой задаче, где все экземпляры будут иметь одинаковые типы.

Mikhail Krassavin 16.11.2018 20:01

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

PaulMcKenzie 16.11.2018 20:02

@MikhailKrassavin, конечно, но он будет указывать на его конкретную версию. Он будет работать только с указанными типами аргументов.

SergeyA 16.11.2018 20:02

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

Yakk - Adam Nevraumont 16.11.2018 20:05

Это известно как проблема X / Y. У вас есть проблема Y. Вы придумываете решение: «Если я могу решить X, я могу решить Y». Затем вы сталкиваетесь с проблемами при решении X (возможно, потому, что это невозможно) и спрашиваете о X. В этом случае ваш X, вероятно, смехотворно сильнее, чем то, что вам нужно для решения Y. Представьте, что вы хотите убить паука. Вы слышите о делении атома и думаете, что паук умрет, если вы взорвете ядерную бомбу. Пытаясь собрать ядерную бомбу, вы сталкиваетесь с проблемами при запуске центрифуг, потому что для мощности у вас есть велосипед. Итак, вы спрашиваете, как запустить урановую центрифугу на велосипеде.

Yakk - Adam Nevraumont 16.11.2018 20:07

Это вопрос: «Как запустить урановую центрифугу на велосипеде». И это правда, если бы вы решили эту проблему, паук действительно был бы мертв. Но эту проблему нельзя решить; так что, пожалуйста, расскажите нам о пауке, которого вы хотите убить. И не говорите: «Есть много миллиардов атомов, расположенных определенным образом, мне нужно рандомизировать». Расскажите нам как можно лучше, что такое паук.

Yakk - Adam Nevraumont 16.11.2018 20:09

@ Yakk-AdamNevraumont, я понимаю, что использовать такой подход до некоторой степени нелепо (конечно, простая функция с фиксированными аргументами будет работать нормально), но мне просто интересно узнать что-то новое.

Mikhail Krassavin 16.11.2018 20:13
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

У вас не может быть указателя на шаблон функции. У вас может быть только указатель на конкретный экземпляр шаблона. Точно так же вы не можете упаковать шаблон в std::function - только его конкретный экземпляр.

И вы можете помещать в контейнер только объекты одного типа, поэтому ваши указатели должны быть одного типа (т.е. функция, на которую они указывают, должна принимать аргументы одного типа и возвращать один и тот же тип).

std::function будет иметь такое же ограничение - все std::functions внутри контейнера должны быть одного типа с точки зрения возвращаемого значения и аргументов.

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