Comments 34
ЗдОрово. А еще можно переписать без лямбд, тогда код будет работать на компиляторах без поддержки C++11. Вот на примере оператора сложения:
Хотя, коряво все это выглядит без лямбд.
func_t operator+ (const func_t &arg, const func_t &arg2)
{
struct _sum
{
_sum(const func_t &arg, const func_t &arg2)
: _arg(arg), _arg2(arg2){}
double operator()(double x)
{
return (*_arg.f)(x) + (*_arg2.f)(x);
}
const func_t& _arg;
const func_t& _arg2;
};
realfunc realf = _sum(arg, arg2);
return func_t(realf);
}
Хотя, коряво все это выглядит без лямбд.
+2
+1
А статический список, если я правильно понял, используется только для вечного хранения realfunc объектов, он всегда растет при конструировании func_t и очищается только по завершении программы? Я бы посмотрел в сторону shared_ptr и хранил бы его вместо realfunc *f, если нет циклических ссылок. Список был бы не нужен.
+2
shared_ptr<realfunc> f;
Угловые скобки съелись.0
Да, это тот факт, с которым я смирился перед тем, как начать писать. Можно, конечно, создавать внешние классы для «цепочек» составления функций. Т.е., я решаю в программе какую-то задачу в созданном специально под эту задачу объекте, а потом удаляю его.
Выглядело бы это примерно так:
Но всё равно со статической коллекцией, пусть не одной.
К сожалению, я не имею ни малейшего представления о shared_ptr.
Выглядело бы это примерно так:
func_chain T1();
T1::func_t f = ...
...
Но всё равно со статической коллекцией, пусть не одной.
К сожалению, я не имею ни малейшего представления о shared_ptr.
0
Я конечно польщён, что моя статья про лямбды натолкнула Вас на такую идею, однако, интуиция мне подсказывает, что можно было всё это сделать проще.
Я правильно понял, что Вы создаёте статическое хранилище функций, которое заполняете в рантайме? о_О Причём, коллекция только заполняется — из неё ничего не удаляется.
Значит, если я создам в своей программе 500 функций, то там будет как минимум 500 объектов (на самом деле больше, т.к. при композиции создаются дополнительные объекты
Как минимум, неплохо бы заменить
А вообще, не могли бы Вы ещё раз объяснить (желательно на примере кода) вот этот абзац, ибо мне кажется, я чего-то не уловил:
Я правильно понял, что Вы создаёте статическое хранилище функций, которое заполняете в рантайме? о_О Причём, коллекция только заполняется — из неё ничего не удаляется.
Значит, если я создам в своей программе 500 функций, то там будет как минимум 500 объектов (на самом деле больше, т.к. при композиции создаются дополнительные объекты
func_t
), причём удалятся они только при завершении работы программы. Как минимум, неплохо бы заменить
std::vector<>
на std::list<>
, а в класс добавить счётчик ссылок, чтобы ненужные функции оттуда удалялись, когда они становятся ненужными.А вообще, не могли бы Вы ещё раз объяснить (желательно на примере кода) вот этот абзац, ибо мне кажется, я чего-то не уловил:
Скажем, мы хотим, чтобы некая процедура принимала пару функций A и B и возвращала новое выражение, например, 5A + B. Наша процедура создаст лямбду 5A, затем создаст 5A + B, используя 5А и В. Полученное процедура вернет и завершится, в этот момент лямбда 5А пропадет из области видимости и возвращенное выражение попросту не будет работать.
+2
Оу, у Вас и так
list<>
. Это я провтычил, но ничего от этого не меняется.0
#include <iostream>
#include <xstddef>
#include <functional>
using namespace std;
typedef tr1::function<double(double)> realfunc;
realfunc go(realfunc &A, realfunc &B)
{
realfunc A5 = [&](double x) {
return A(x) * 5;
};
realfunc A5pB = [&](double x) {
return A5(x) + B(x);
};
return A5pB;
}
int main()
{
realfunc A = [&](double x) {
return x;
};
realfunc B = [&](double x) {
return x;
};
realfunc A5pB = go(A, B);
cout << A5pB(3) << endl;
getchar();
}
Вот тут рантайм. А если go() возвращает A5, то всё в порядке.
=(
0
#include <cstddef>
#include <functional>
#include <iostream>
using namespace std;
typedef function<double(double)> realfunc;
realfunc go(realfunc A, realfunc B)
{
return [=](double x) {
return A(x) * 5 + B(x);
};
}
int main()
{
realfunc A = [](double x) {
return x;
};
realfunc B = [](double x) {
return x;
};
auto A5pB = go(A, B);
cout << A5pB(3) << endl;
return EXIT_SUCCESS;
}
+1
Ну так вы в фукнции go() создаете единственный объект и его же копию возвращаете. В моем примере проблема была в потере А5.
0
Сделайте лямбду
[=]
вместо [&]
и всё будет работать.+1
Да, но идея передавать везде все по копированию мне изначально не понравилась. Например, я создам одну гигантскую функцию и сотню маленьких, использующих ее. В моем случае гигансткая будет в одном экземпляре в коллекции, а в вашем, наверное, не в одном.
Сейчас вы скажете, что я совершенно не понимаю механизма всех этих штук, и я не возражу.
Сейчас вы скажете, что я совершенно не понимаю механизма всех этих штук, и я не возражу.
0
Однозначного ответа я Вам не дам, но не исключаю вариант, что компилятор оптимизирует подобные места за счёт Copy Elision хотя бы.
+1
Попробуйте оба варианта в релизе с максимальной настройкой оптимизации компилятора, сделайте замеры производительности на хорошо нагруженном примере и сравните. Если [=] окажется не менее производительным, чем [&], выбрасывайте список, код упростится.
+1
Размер функции не зависит от размера ее кода, только от того, что она захватывает. И проще сделать так, чтобы гигантская функция захватывала по ссылке нужные данные (и shared_ptr лучше static), а не ее саму захватывать по ссылке.
Зато в случае захвата = будет рядом храниться все что надо и это будет быстрее. Память дешевая, дорого обходятся кэш-промахи и локальность данных важнее.
А лучший подход — boost phoenix, если динамичность не нужна
Зато в случае захвата = будет рядом храниться все что надо и это будет быстрее. Память дешевая, дорого обходятся кэш-промахи и локальность данных важнее.
А лучший подход — boost phoenix, если динамичность не нужна
0
Вот если бы оно умело какие-нибудь простейшие преобразования типа a — a = 0, a + 0 = a, a * (b + c) = a * c + b * c. Коли речь зашла о производных, то было бы полезно выводить производные элементарных функций, а не пытаться их аппроксимировать, да еще и не очень точно.
0
Это крайне похоже на Expression Templates, которые используются давно (лет 15) и замечательно обходятся без лямбд.
+2
Название статьи прочитал как «Динамический мат». Задумался
-3
Мне кажется, вместо указателя удобнее использовать итератор, можно будет тогда и из списка удалять при необходимости. И, как уже говорили, посмотрите в сторону shared_ptr.
Вот конструктор копирования угнетает. Зачем Вы еще одну копию кидаете в список? Можно ведь просто скопировать себе указатель.
Вот конструктор копирования угнетает. Зачем Вы еще одну копию кидаете в список? Можно ведь просто скопировать себе указатель.
0
[quote]
Скажем, мы хотим, чтобы некая процедура принимала пару функций A и B и возвращала новое выражение, например, 5A + B. Наша процедура создаст лямбду 5A, затем создаст 5A + B, используя 5А и В. Полученное процедура вернет и завершится, в этот момент лямбда 5А пропадет из области видимости, и возвращенное выражение попросту не будет работать.
[/quote]
Можно создать лямбду 5A внутри результирующей 5A + B, тогда этой проблемы не будет.
Скажем, мы хотим, чтобы некая процедура принимала пару функций A и B и возвращала новое выражение, например, 5A + B. Наша процедура создаст лямбду 5A, затем создаст 5A + B, используя 5А и В. Полученное процедура вернет и завершится, в этот момент лямбда 5А пропадет из области видимости, и возвращенное выражение попросту не будет работать.
[/quote]
Можно создать лямбду 5A внутри результирующей 5A + B, тогда этой проблемы не будет.
0
Математические функции еще отличаются чистотой, а переменные — иммутабельностью. Короче говоря берите любой функциональный язык и наслаждайтесь.
0
>Ну да, как это использовать.
>Например вот так:
>func_t f1 = cos(5 * func_t() + 8);
>это создаст, как видно, функцию
>f1(x) = cos(5x + 8)
Для тренировки полезно: пока все это заработает, надо достаточно много тонких моментов вспомнить. Только в реальных проектах этим лучше не пользоваться. Лучше:
=)
>Например вот так:
>func_t f1 = cos(5 * func_t() + 8);
>это создаст, как видно, функцию
>f1(x) = cos(5x + 8)
Для тренировки полезно: пока все это заработает, надо достаточно много тонких моментов вспомнить. Только в реальных проектах этим лучше не пользоваться. Лучше:
double f1 (double x) { return cos(5*x + 8); }
=)
0
Sign up to leave a comment.
Динамические мат. функции в C++