компактная запись 2
От: dad  
Дата: 29.07.15 11:16
Оценка:
есть набор функций/методов возвращающих целое число.
есть функция/метод возвращающий сумму результатов или 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;


подставит-ли компилятор лямбда функцию оптимально?
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Отредактировано 29.07.2015 11:24 dad . Предыдущая версия . Еще …
Отредактировано 29.07.2015 11:17 dad . Предыдущая версия .
Re: компактная запись 2
От: watchmaker  
Дата: 29.07.15 11:46
Оценка: 25 (2)
Здравствуйте, dad, Вы писали:

dad>подставит-ли компилятор лямбда функцию оптимально?


Может сам убедится тут, что как минимум у gcc, clang и icc с такой подстановкой проблем нет.
Re[2]: компактная запись 2
От: dad  
Дата: 29.07.15 11:48
Оценка:
W>Может сам убедится тут, что как минимум у gcc, clang и icc с такой подстановкой проблем нет.

шикарный совт, спасибо.
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re: компактная запись 2
От: Mr.Delphist  
Дата: 29.07.15 11:52
Оценка:
Здравствуйте, dad, Вы писали:

dad>есть набор функций/методов возвращающих целое число.

dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :

Оно? http://stackoverflow.com/questions/20028936/is-there-a-accummulate-if
Re[2]: компактная запись 2
От: dad  
Дата: 29.07.15 11:55
Оценка:
W>с такой подстановкой проблем нет.

с if код куда меньше инструкций содержит http://goo.gl/RcEJfW
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[2]: компактная запись 2
От: dad  
Дата: 29.07.15 11:57
Оценка:
MD>Оно? http://stackoverflow.com/questions/20028936/is-there-a-accummulate-if

примерно оно, но итератора вызовов нет, и его организация явно не добавит наглядности кода
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re: компактная запись 2
От: BulatZiganshin  
Дата: 29.07.15 12:07
Оценка:
Здравствуйте, dad, Вы писали:

dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?


пропроцессор с variadic macros
Люди, я люблю вас! Будьте бдительны!!!
Re[3]: компактная запись 2
От: watchmaker  
Дата: 29.07.15 12:13
Оценка: +1
Здравствуйте, dad, Вы писали:


W>>с такой подстановкой проблем нет.


dad>с if код куда меньше инструкций содержит http://goo.gl/RcEJfW


Так семантика программ различается. Вот пара главных отличий:

Так что перед сравнением стоит привести программы так, чтобы они считали одни и те же величины, например http://goo.gl/h4w6Jo и http://goo.gl/wdQcGu
Отредактировано 29.07.2015 12:23 watchmaker . Предыдущая версия .
Re[4]: компактная запись 2
От: dad  
Дата: 29.07.15 12:20
Оценка:
W>Так семантика программы различается. Вот пара главных отличий:
W>

виноват — проглядел отсутствие инициализации. с инициализацией кол-во инструкций стало даже больше.
да — и 2 тоже верно.

спасибо!
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Отредактировано 29.07.2015 12:21 dad . Предыдущая версия .
Re[3]: компактная запись 2
От: Mr.Delphist  
Дата: 29.07.15 15:33
Оценка:
Здравствуйте, dad, Вы писали:

MD>>Оно? http://stackoverflow.com/questions/20028936/is-there-a-accummulate-if


dad>примерно оно, но итератора вызовов нет, и его организация явно не добавит наглядности кода


Ну, наглядность в STL — тема отдельного холивара (ИМХО, просто требует некоторой тренировки). А так — таки да, pure STL way: имеем контейнер функций, бежим по нему, исполняем, валидируем условие продолжения, переходим дальше или возвращаем накопленное.
Re: компактная запись 2
От: VTT http://vtt.to
Дата: 29.07.15 18:48
Оценка: :)
Здравствуйте, dad, Вы писали:

dad>есть набор функций/методов возвращающих целое число.

dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :

dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?

  магия
class
t_AccumulateWhileNonZeroImpl
{
    #pragma region Fields

    protected: int & m_sum;
    protected: bool  m_continue = true;

    #pragma endregion

    private:
    t_AccumulateWhileNonZeroImpl(void) = delete;

    private:
    t_AccumulateWhileNonZeroImpl(t_AccumulateWhileNonZeroImpl const &) = delete;

    private:
    t_AccumulateWhileNonZeroImpl(t_AccumulateWhileNonZeroImpl && other) throw()
    :    m_sum(other.m_sum)
    {
        // do nothing...        
    }

    private: explicit
    t_AccumulateWhileNonZeroImpl(int & sum) throw()
    :   m_sum(sum)
    {
        m_sum = 0;
    }

    private: auto
    operator =(t_AccumulateWhileNonZeroImpl const &) -> void = delete;

    private: auto
    operator =(t_AccumulateWhileNonZeroImpl &&) -> void = delete;

    public: template<typename tp_Method> auto
    operator ,(tp_Method & method) -> t_AccumulateWhileNonZeroImpl &
    {
        if(m_continue)
        {
            auto const method_result(method());
            m_continue = (0 != method_result);
            m_sum += method_result;
        }
        return(*this);
    }

    friend auto
    Accumulate_While_NonZero(int & sum) throw() -> t_AccumulateWhileNonZeroImpl;
};

auto
Accumulate_While_NonZero(int & sum) throw() -> t_AccumulateWhileNonZeroImpl
{
    return(t_AccumulateWhileNonZeroImpl(sum));
}
int Give_9(void) {return 9;}
int Give_0(void) {return 0;}

int sum;
Accumulate_While_NonZero(sum), Give_9, Give_9, Give_0, Give_9;
assert(18 == sum);
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Отредактировано 03.08.2015 7:59 VTT . Предыдущая версия .
Re: компактная запись 2
От: Abyx Россия  
Дата: 30.07.15 10:59
Оценка: +1
Здравствуйте, dad, Вы писали:

dad>есть набор функций/методов возвращающих целое число.

dad>есть функция/метод возвращающий сумму результатов или 0 в случае, если хотя-бы один метод вернул 0 :

dad>
dad>int f1();
dad>int f2();
dad>int f3();

dad>int acc()
dad>{   
dad>  int rez;
dad>  int r;
dad>  if (!(r = f1())) return 0;
dad>  rez += r;
dad>  if (!(r = f2())) return 0;
dad>  rez += r;
dad>  if (!(r = f3())) return 0;
dad>  rez += r;
dad>  return rez;
dad>}
dad>


dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?


int acc() {
  int sum;
  for (auto f : {f1, f2, f3}) {
    auto n = f();
    if (n == 0) return 0;
    sum += n;
  }
  return sum;
}


или

int acc() {
  int r1, r2, r3;
  if ((r1 = f1()) && (r2 = f2()) && (r3 = f3()))
    return r1 + r2 + r3;
  return 0;
}
In Zen We Trust
Re: компактная запись 2
От: Кодт Россия  
Дата: 30.07.15 11:01
Оценка: :)
Здравствуйте, 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));


Либо на цикле (чтобы быстро завершить accumulate)
int xs[] = { f1(), f2(), f3(), ..... }; // энергичный случай
F fs[] = { f1, f2, f3, ..... }; // ленивый случай

int acc = 0;
for(x : xs) {
  if(!x) { acc = 0; break; }
  acc += x;
}

for(f : fs) {
  int x = f();
  if(!x) { acc = 0; break; }
  acc += x;
}


Либо тупо на макросах
// optional для бедных
bool ok = true;
int acc = 0;

#define ADD(expr)          \
  do {                     \
    if(ok)                 \
      if(int tmp = (expr)) \
        acc += tmp;        \
      else {               \
        acc = 0;           \
        ok = false;        \
      }                    \
  } while(false)

ADD(f1());
ADD(f2());
ADD(f3());

Либо даже так
int acc;
#define BEGIN() do { acc = 0;
#define ADD(expr) if(tmp = (expr)) acc += tmp; else { acc = 0; break; }
#define END() while(false);

BEGIN()
  ADD(f1())
  ADD(f2())
  ADD(f3())
END()

Если функций много, и вызовы их выглядят одинаково, то нагенерить серию ADD-ов можно с помощью BOOST_PP.

В общем, простор!
Перекуём баги на фичи!
Re[2]: компактная запись 2
От: dad  
Дата: 30.07.15 11:22
Оценка:
Здравствуйте, Кодт, Вы писали:

да — ленивые.
можно что-нибудь с initializer_list или переменным числом параметров — но в таком виде компактности и наглядности не наблюдаю ))
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re: компактная запись 2
От: andrey.desman  
Дата: 31.07.15 14:13
Оценка: 4 (1)
Здравствуйте, dad, Вы писали:

dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?


int f()
{
   int r;
   int rez = 0;

   return true
      && (r = f1(), rez += r, r)
      && (r = f2(), rez += r, r)
      && (r = f3(), rez += r, r)
      ? rez : 0;
}
Re: компактная запись 2
От: Sni4ok  
Дата: 03.08.15 07:45
Оценка:
Здравствуйте, dad, Вы писали:


dad>как сделать более компактную, но и удобную для добавления/удаления f* запись (с использованием любых инструментов c|c++) ?


#include <boost/preprocessor/seq.hpp>

int f1();
int f2();
int f3();

#define FUNCS (f1)(f2)(f3)

int acc()
{
  int rez;
  int r;

#define PROCEED_FUNC(a, b, elem) \
  if (!(r = elem())) return 0; \
  rez += r;

  BOOST_PP_SEQ_FOR_EACH(PROCEED_FUNC,,FUNCS)

  return rez;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.