В библиотеке диапазонов есть два вида операций:
- представления , которые ленивы и требуют наличия нижележащего контейнера.
- действия которые стремятся и в результате производят новые контейнеры (или изменяют существующие)
Представления облегчены. Вы передаете их по значению и требуете, чтобы базовые контейнеры оставались действительными и неизменными.
Из документации range-v3
Представление - это облегченная оболочка, которая представляет представление базовой последовательности элементов некоторым пользовательским способом, не изменяя и не копируя его. Представления дешевы в создании и копировании и имеют несобственную семантику ссылок.
и:
Любая операция с базовым диапазоном, которая делает недействительными его итераторы или стражи, также делает недействительными любое представление, которое относится к любой части этого диапазона.
Разрушение нижележащего контейнера, очевидно, делает недействительными все итераторы к нему.
В вашем коде вы специально используете views - Вы используете ranges::views::transform
. Трубка - просто сахар syntacti c, позволяющий легко писать, как она есть. Вы должны посмотреть на последнюю вещь в трубе, чтобы увидеть, что вы производите - в вашем случае это представление.
Если бы не было оператора трубы, это, вероятно, выглядело бы примерно так:
ranges::views::transform(my_custom_rng_gen(some_param), my_transform_op)
если бы было подключено несколько преобразований таким образом, вы можете увидеть, насколько уродливым это будет.
Таким образом, если my_custom_rng_gen
создаст какой-то контейнер, который вы преобразуете и затем возвращаете, этот контейнер разрушается, и у вас есть свисающие ссылки с вашей точки зрения. Если my_custom_rng_gen
- это другое представление для контейнера, который находится за пределами этих областей, все в порядке.
Однако компилятор должен быть в состоянии распознать, что вы применяете представление к временному контейнеру, и ударить вас ошибка компиляции.
Если вы хотите, чтобы ваша функция возвращала диапазон как контейнер, вам нужно явно "материализовать" результат. Для этого используйте оператор ranges::to
внутри функции.
Обновление: Чтобы быть более точным в отношении вашего комментария ", где в документации сказано, что составление диапазона / трубопровод берет и сохраняет представление? "
Труба - это просто синтактический c сахар для соединения вещей в легко читаемом выражении. В зависимости от того, как он используется, он может возвращать или не возвращать представление. Это зависит от аргумента правой части. В вашем случае это:
`<some range> | ranges::views::transform(...)`
Таким образом, выражение возвращает то, что возвращает views::transform
.
Теперь, читая документацию преобразования:
Ниже приведен список ленивых комбинаторов диапазонов или представлений, которые предоставляет Range-v3, и реклама о том, как каждый из них предназначен для использования.
[...]
views::transform
Если задан диапазон источника и унарная функция, вернуть новый диапазон, где каждый элемент результата является результатом применения унарной функции к элементу источника.
Таким образом, он возвращает диапазон, но поскольку он является ленивым оператором, этот диапазон он возвращает - это представление со всей его семантикой.