Почему диапазоны С++ 20 не предоставляют только синтаксис канала?

Я понимаю, что этот вопрос звучит странно, так что вот немного контекста.

Недавно я был разочарован, узнав, что уменьшение карты в диапазонах С++ 20 не работает, как можно было бы ожидать, т.е.

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

не работает, вы должны написать это неестественным способом:

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

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

Так что это заставило меня задуматься:

Если C++20 требует, чтобы вы использовали канал для использования диапазонов, иначе вы не можете не писать

vector<int> v;
sort(v);

но ты должен написать

vector<int> v
v|sort();

решит ли это проблему двусмысленности?

И если это так, хотя это и неестественно для людей, использующих std::sort и другие алгоритмы STL, мне интересно, будет ли в долгосрочной перспективе это лучшим выбором дизайна.

Примечание. Если этот вопрос слишком расплывчатый, не стесняйтесь проголосовать за закрытие, но я чувствую, что это законный вопрос дизайна, на который можно ответить относительно непредвзято, особенно если я неправильно понимаю проблему.


person NoSenseEtAl    schedule 08.12.2019    source источник
comment
Какие два различных варианта использования не могут быть устранены неоднозначно? Если вы этого не объясните, мы не сможем понять ваш итоговый вопрос.   -  person einpoklum    schedule 09.12.2019
comment
@einpoklum-reinstateMonica Я предоставил ссылку, я посчитал ее слишком подробной, чтобы ее можно было встроить: stackoverflow.com/questions/59130785/   -  person NoSenseEtAl    schedule 09.12.2019
comment
ИМХО можно в двух предложениях резюмировать. В SO принято не слишком полагаться на содержимое ссылок. Во всяком случае, я понимаю, что вы имеете в виду; но мой ответ стоит на общих основаниях.   -  person einpoklum    schedule 09.12.2019


Ответы (2)


решит ли это проблему двусмысленности?

Да.

Если есть только один способ написать что-то, этот единственный способ должен быть единственно возможной интерпретацией. Если «вызов» алгоритма может быть только частичным вызовом алгоритма, который должен быть завершен операцией | с диапазоном в левой части, то у вас даже не возникнет вопроса о том, является ли вызов алгоритма частичным или общий. Просто всегда частично.

Никакой двусмысленности в этом смысле.

Но если вы пошли по этому пути, вы получите такие вещи, как:

auto sum = accumulate("hello"s);

Что на самом деле не суммирует char в этой строке, а фактически является заполнителем, который ожидает накопления диапазона с начальным значением "hello"s.

person Barry    schedule 08.12.2019
comment
С большой грустью я принимаю ваш ответ, я надеялся, что я что-то неправильно понял. :/ - person NoSenseEtAl; 12.12.2019

Необходимо различать алгоритмы диапазона и адаптеры диапазона. Алгоритмы — это функции, которые выполняют общую операцию над диапазоном значений. Адаптеры — это функции, которые создают представления диапазонов, которые изменяют представление диапазона. Адаптеры связаны оператором |; алгоритмы - это обычные функции.

Иногда одна и та же концептуальная вещь может иметь форму алгоритма и адаптера. transform существует и как алгоритм, и как адаптер. Первый сохраняет преобразование в выходной диапазон; последний создает диапазон просмотра ввода, который лениво вычисляет преобразование в соответствии с запросом.

Это разные задачи для разных нужд и применений.

Также обратите внимание, что в C++20 нет sort адаптера. Адаптер сортировки должен был бы создать диапазон просмотра, который каким-то образом смешал элементы в исходном диапазоне. Ему нужно будет выделить память для новой последовательности значений (даже если это просто сортировка итераторов/указателей/индексов к значениям). И сортировка должна быть сделана во время строительства, чтобы не было ленивых операций.

Вот почему accumulate так не работает. Дело не в «двусмысленности»; это вопрос фундаментального характера операции. Накопление вычисляет значение из диапазона; он не вычисляет новый диапазон из существующего. Это работа алгоритма, а не адаптера.

Некоторые задачи полезны в форме алгоритма. Некоторые задачи полезны в форме адаптера (вы найдете очень мало zip-подобных алгоритмов). Некоторые задачи полезны в обоих случаях. Но поскольку это две отдельные концепции для разных целей, у них есть разные способы их вызова.

person Nicol Bolas    schedule 08.12.2019
comment
ОП не утверждает, что вы не можете это написать. ОП предлагает гипотетический дизайн, а вы не могли. - person Barry; 09.12.2019
comment
@Barry: Смотри мой последний абзац. Вот почему это разные задачи для разных нужд. - person Nicol Bolas; 09.12.2019
comment
Я не понимаю, что вы пытаетесь сделать в последнем абзаце (что раньше было таковым). range-v3 давайте напишем get_data() | actions::sort - я не вижу в | ничего такого, что запрещало бы мне делать подобные действия, если бы я так захотел. - person Barry; 09.12.2019
comment
@Barry: Теперь вы вступаете в совершенно отдельный разговор: действия, которые представляют собой концепцию, отличную от адаптеров и алгоритмов. - person Nicol Bolas; 09.12.2019
comment
Они вообще не разделены? На самом деле я не верю, что какие-либо из этих вещей значимы, особенно когда речь идет о синтаксисе. Адаптер диапазона — это ленивый алгоритм, а действие — энергичный алгоритм, где адаптеры и действия берут и производят диапазоны. Что такого фундаментального в аккумуляции, что data | transform(f) | filter(g) | accumulate не может быть действительным? Это довольно разумная вещь, которую нужно сделать, и она отлично работает на других языках/библиотеках. - person Barry; 09.12.2019
comment
@Barry: Что принципиального в накоплении, что data | transform(f) | filter(g) | accumulate не может быть действительным? Мне вообще не нравится идея, что у нас есть куча вещей, которые принципиально делают концептуально разные вещи, которые мы собираемся притворяться это одно и то же. accumulate вычисляет значение; другие строят представления диапазона. accumulate действует мгновенно на заданном диапазоне; остальные оценивают лениво. Это то, что делает их принципиально разными. Мне нравится идея, что | означает просмотр диапазона, а не применение произвольной функции к этой другой вещи. - person Nicol Bolas; 09.12.2019