есть набор функций/методов возвращающих целое число.
есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :
int f1();
int f2();
int f3();
int acc()
{
int rez;
int r;
if (!(r = f1())) return 0;
rez += r;
if (!(r = f2())) return 0;
rez += r;
if (!(r = f3())) return 0;
rez += r;
return rez;
}
как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?
вот такой вариант, например:
int rez = 0;
auto _acc = [&](int r) -> bool {
return r ? rez += r : 0;
};
return
_acc(f1()) &&;
_acc(f2()) &&;
_acc(f3()) ? rez : 0;
Здравствуйте, dad, Вы писали:
dad>есть набор функций/методов возвращающих целое число. dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :
Здравствуйте, dad, Вы писали:
dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?
W>>с такой подстановкой проблем нет.
dad>с if код куда меньше инструкций содержит http://goo.gl/RcEJfW
Так семантика программ различается. Вот пара главных отличий:
В твоём варианте с if пропущена инициализация переменной rez. То есть тут UB. А компилятор же просто удаляет всю логику суммирования, но при этом следит за порядком вызовов функций f1,f2,f3 — так как именно там находятся пути, приводящие к return 0, то есть к веткам независящим от мусора в rez;
Условие !(r = f2()) прекращает вычисления если f2 вернула 0. В твоём же варианте с лямбдами условие другое: r ? rez += r : 0, то есть вычисления заканчиваются и в том случае, если сумма стала нулевой (рассмотри, например, случай f1() == -5, f2() == 5).
W>Так семантика программы различается. Вот пара главных отличий: W>
В твоём варианте с if пропущена инициализация переменной rez. То есть тут UB. А компилятор же просто удаляет всю логику суммирования, но при этом следит за порядком вызовов функций f1,f2,f3 — так как именно там находятся пути, приводящие к return 0, то есть к веткам независящим от мусора в rez;
W>Условие !(r = f2()) прекращает вычисления если f2 вернула 0. В твоём же варианте с лямбдами условие другое: r ? rez += r : 0, то есть вычисления заканчиваются и в том случае, если сумма стала нулевой (рассмотри, например, случай f1() == -5, f2() == 5). W>
виноват — проглядел отсутствие инициализации. с инициализацией кол-во инструкций стало даже больше.
да — и 2 тоже верно.
спасибо!
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Ну, наглядность в STL — тема отдельного холивара (ИМХО, просто требует некоторой тренировки). А так — таки да, pure STL way: имеем контейнер функций, бежим по нему, исполняем, валидируем условие продолжения, переходим дальше или возвращаем накопленное.
Здравствуйте, dad, Вы писали: dad>есть набор функций/методов возвращающих целое число. dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 : dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?
Здравствуйте, dad, Вы писали:
dad>есть набор функций/методов возвращающих целое число. dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :
dad>
Здравствуйте, dad, Вы писали:
dad>есть набор функций/методов возвращающих целое число. dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :
Если нужно (или можно) энергичное вычисление результатов, то
// в допущении, что аргументы положительные, и нет переполненияint plus0(int acc, int x) {
return acc && x ? acc + x : 0;
}
int seed() { return 1; }
int commit(int acc) { return acc ? acc-1 : 0; }
// без этого допущенияusing boost::optional; // или std::experimental::optional;
// или переделать на std::pair<bool,int>
optional<int> plus0(optional<int> acc, int x) {
return acc && x ? optional<int>(*acc + x) : optional<int>();
}
optional<int> seed() { return optional<int>(0); }
int commit(optional<int> acc) { return acc ? *acc : 0; }
....
int xs[] = { f1(), f2(), f3(), ..... };
return commit(std::accumulate(std::begin(xs), std::end(xs), seed(), plus0));
Если нужно ленивое,
то заменить массив результатов на массив функций и вызывать их по необходимости
// чисто для упрощенияtypedef int (*F)();
int plus0(int acc, F f) {
if(!acc) return 0;
int x = f();
if(!x) return 0;
return acc+x;
}
.....
F fs[] = { f1, f2, f3, ..... };
return commit(std::accumulate(std::begin(fs), std::end(fs), seed(), plus0));
Здравствуйте, dad, Вы писали:
dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?