Почему ranges::accumulate не передает init как std::move(init) при вызове?

На момент фиксации d5e9afc 17 марта 2018 года accumulate.hpp

При передаче диапазона init получает std::move один раз, как это.

        T operator()(Rng && rng, T init, Op op = Op{}, P proj = P{}) const
        {
            return (*this)(begin(rng), end(rng), std::move(init), std::move(op),
                std::move(proj));
        }

Приведенный выше код вызовет это:

        T operator()(I begin, S end, T init, Op op = Op{}, P proj = P{}) const
        {
            for(; begin != end; ++begin)
                init = invoke(op, init, invoke(proj, *begin)); // why do we need this another copy of init?
            return init;
        }

Интересно, зачем нам эта еще одна копия инициализации перед вызовом вызова?

Этот init должен быть переопределен в любом случае, верно? Так почему же это не нормально, чтобы сорвать его в первую очередь?

                init = invoke(op, std::move(init), invoke(proj, *begin));

person sandthorn    schedule 24.04.2018    source источник
comment
invoke принимает по значению?   -  person StoryTeller - Unslander Monica    schedule 24.04.2018
comment
@StoryTeller Зачем запрещать перемещение вещей в качестве параметров?   -  person sandthorn    schedule 24.04.2018
comment
Я предполагаю, что init должен быть примитивным типом, поэтому передача по значению может быть более эффективной.   -  person Galik    schedule 24.04.2018
comment
@Galik Перенос непримитивных налогов на дополнительные циклы? Или библиотека пытается поощрять использование init в качестве премитива? или оба?   -  person sandthorn    schedule 24.04.2018


Ответы (1)


Этот фрагмент кода пытается избежать предположения о C++17. std::move-ing init потенциально может изменить его (в конце концов, для этого и нужна семантика движений). И это оставляет нам что-то вроде этого:

init = /* An expression that maybe modifies init */;

Это привело бы к неопределенному поведению до C++17. range-v3 также рекламирует себя как библиотеку для C++11 и C++14.

person StoryTeller - Unslander Monica    schedule 24.04.2018
comment
Если это только то, как вы думаете, добавят ли они макрос C++ 17+, который двигается? - person sandthorn; 24.04.2018
comment
@sandthorn - IDK, я не в их голове :) Это проект с открытым исходным кодом, отправьте им запрос на включение, если вы видите возможности для улучшения. - person StoryTeller - Unslander Monica; 24.04.2018
comment
undefined behavior prior to C++17 Не могли бы вы указать, в каком разделе стандарта C++14 явно указано значение undefined? - person sandthorn; 24.04.2018
comment
@sandthorn - это уже упоминалось на SO. См. здесь. - person StoryTeller - Unslander Monica; 24.04.2018
comment
Немного почитав, я узнал, что std::accumulate требует CopyConstructible от init, так что это нужно оставить как есть, пока день std не изменится сам по себе. Более того, я думаю, у range-v3 есть желание пожаловаться на <numeric>. Однако теперь std::reduce требует инициализации MoveConstructible!!. Ну, похоже, реализации пока нет. - person sandthorn; 24.04.2018