Могу ли я подключиться к range-v3 для накопления?

Я нашел более старые вопросы 3-летней давности, в которых говорится, что в целом это невозможно, но мне бы очень хотелось, чтобы конвейер накапливался, поскольку в некоторых случаях это довольно приятно, например это:

const double val = data | transform(...) | accumulate (...);

Поэтому мне интересно, было ли что-то добавлено в диапазоны range-v3/C++20, что позволяет мне это делать.


person NoSenseEtAl    schedule 01.12.2019    source источник


Ответы (1)


No.

Единственное, что вы можете передать, это адаптеры диапазона — алгоритмы, которые принимают диапазон и производят диапазон. Алгоритмы, которые принимают диапазон и возвращают один объект (также известные как катаморфизмы), не поддерживают конвейер в диапазонах range-v3 или C++20.

Вы должны написать это так:

const double val = accumulate(data | transform(...));

Что касается того, почему accumulate и подобные алгоритмы будут изо всех сил пытаться когда-либо быть |-способными. Учтите, что мы хотим, чтобы algo(rng, x) и rng | algo(x) означали одно и то же. Кроме того, учтите, что «полный вызов» algo(rng, x) может быть полностью ограничен (поскольку у вас есть вся информация), в то время как «частичный вызов» algo(x) в основном должен быть полностью неограничен во всех, кроме редких случаях... в основном примерно принимая auto&&...

Проблема в том, что мы неизбежно сталкиваемся с неясностями, когда второй аргумент, x, может также быть диапазоном. Как вы различаете, является ли намерение полным вызовом или частичным вызовом?

Вот пример использования string:

accumulate("hello"s, ""s)

Это общий вызов, в котором используется двоичный оператор по умолчанию +, представляющий собой конкатенацию строк. Это перебирает элементы диапазона chars и добавляет их один за другим в исходную пустую строку. Это неэффективный, но правильный способ скопировать файл string. Вы получите значение "hello"s.

А как насчет его эквивалентной версии с трубой?

"hello"s | accumulate(""s)

Что означает правая сторона? Можно ли считать accumulate(""s) полным вызовом? Да, оно может! 2-й аргумент по умолчанию будет char(), а третий аргумент по умолчанию будет plus(), это работает нормально, и поэтому значение accumulate(""s) равно целому числу 0, что делает все выражение неправильным, потому что нет operator|(string, int).

Как вы заставляете это работать с accumulate?

person Barry    schedule 02.12.2019
comment
ох... это действительно уродливо... Я предполагаю, что у них была веская причина, но я ее не вижу (вероятно, какие-то проблемы в общем случае, и они не хотели делать исключение для накопления). - person NoSenseEtAl; 02.12.2019
comment
@NoSenseEtAl Добавлено объяснение, почему вы не можете сделать accumulate конвейерным. - person Barry; 03.12.2019
comment
Я предполагаю, что ленивая оценка аккумулирования, когда она позже решает, что она хочет сделать, была рассмотрена, но отклонена, потому что она ужасно работала бы с auto(та же проблема, что и с шаблонами выражений, где Matrix m = что-то; отличается от auto m = что-то; поскольку вы нужно запускать конверсию вручную?) - person NoSenseEtAl; 04.12.2019