Почему c++ для каждого цикла принимает r-значения, а std::ranges — нет?

Такой оператор компилируется без ошибок:

for (int i : std::vector<int>({0, 1}))
  std::cout << i;

Но такое заявление не делает:

std::vector<int>({0, 1}) |
  std::views::filter([](int i) { return true; });

Почему r-значения разрешены для каждого цикла, но не для каналов std::range? Есть ли способ заставить что-то вроде второго работать без объявления переменной?

Пожалуйста, опубликуйте сообщение об ошибке, которое создает второй случай.

gerum 19.03.2022 09:39

И лямбда должна возвращать логическое значение, чтобы быть допустимым предикатом.

gerum 19.03.2022 09:44

Я думаю, что std::views::filter пытается защитить вас от создания представления, основанного на уничтоженном временном

Alan Birtles 19.03.2022 09:51

Это разрешено в C++23.

康桓瑋 19.03.2022 11:40

@康桓瑋 Можете уточнить, что изменилось?

HolyBlackCat 19.03.2022 11:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
5
172
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Цикл for работает нормально, потому что vector<int> (rvalue) действителен, пока цикл оценивается.

Второй фрагмент кода имеет 2 проблемы:

  • Предикат должен возвращать bool
  • vector<int>, который вы используете в объекте представлений, к моменту его оценки болтается, поэтому компилятор его не принимает.

Если вместо vector<int> rvalue объект не может болтаться (lvalue) или содержит ссылки на что-то еще, что не может не болтаться, это сработает.

Например:

auto vec = std::vector<int>({0, 1});
auto vw = vec | std::ranges::views::filter([](int i) { std::cout << i; return true; });

Или вы можете передать rvalue со ссылками на независающий объект vector<int>, например std::span:

auto vec = std::vector<int>({0, 1});
auto vw = span{vec} | std::ranges::views::filter([](int i) { std::cout << i; return true; })

Здесь std::span все еще является rvalue, но компилятор принимает его, потому что автор std::span создал для него исключение.

Для пользовательского типа со ссылками на что-то другое (обычно представления) вы можете создать собственное исключение, создав специализацию переменной шаблона enable_borrowed_range.

В случае вектора это будет выглядеть так (но не делай этого!):

template<> // don't do this
inline constexpr bool ranges::enable_borrowed_range<std::vector<int>> = true;

Теперь ваш код компилируется, но он вызовет неопределенное поведение, потому что вектор зависает после оценки представления.

Это работает с последними версиями MSVC STL и libstdc++ (демо) благодаря P2415R2.

До P2415R2 filter_view всегда сохраняет базовый vector по ссылке (через ref_view). Было сочтено неразумным хранить копию vector. Потому что представление должно быть дешевым для копирования, дешевого перемещения и дешевого уничтожения. Хранение копии vector приведет к неожиданному снижению производительности.

И из-за проблем со сроком службы не имеет смысла иметь ссылку на rvalue vector.

Но P2415R2 указывает, что вид также может быть не копируемым, но при этом его можно дешево перемещать и достаточно дешево уничтожать.

Поэтому P2415R2 представил owning_view, некопируемое представление, в котором хранится копия диапазона rvalue, и заставил стандартные адаптеры диапазона использовать это представление.

Конечным результатом является то, что создание filter_view из vector rvalue работает с реализациями стандартной библиотеки, которые реализуют P2415R2.

Я использую GCC 11.1.0. Я так понимаю это будет в новой версии? Можете ли вы придумать какие-либо обходные пути? Лучшее, что у меня есть, это использовать синглтон, но мы многопоточные.

dromodel 19.03.2022 19:44

Другие вопросы по теме