Я использую GCC 14 в режиме C+23. В следующем коде я создаю представление представлений пар, которое затем выравниваю с помощью view::join и помещаю в вектор:
auto c = std::ranges::views::iota(1, 5)
| std::ranges::views::transform([](int const v){
return std::ranges::views::iota(1, 3)
| std::ranges::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::ranges::views::join
| std::ranges::to<std::vector>();
Результатом является вектор пар.
Теперь вместо вектора пар я хотел бы создать карту (или unordered_map). Построение карты из ряда пар должно работать (, как я узнал из своего старого вопроса ). Но здесь это не компилируется:
auto c = std::ranges::views::iota(1, 5)
| std::ranges::views::transform([](int const v){
return std::ranges::views::iota(1, 3)
| std::ranges::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::ranges::views::join
| std::ranges::to<std::map>();
К сожалению, вывод компилятора мне не совсем понятен. Все, что я получил от него, это то, что он не может вызвать std::construct_at для создания узла карты, но я не могу многого понять из всех внутренних устройств стандартной библиотеки.
Использование только одного уровня «вложенных» диапазонов работает как положено. Таким образом, эта проблема возникает только тогда, когда вложенные уровни диапазона объединяются и преобразуются в карту.
Как заставить второй код компилироваться и работать как положено?
libstdc++ в настоящее время не реализует диапазонную версию конструктора map
, а именно map(std::from_range_t, R&&)
, и поскольку создаваемый вами объединенный диапазон не является common_range
, ranges::to
отправит маркер (2.1.4) для первого построения по умолчанию map
, а затем поместите элементы в map
через c.emplace(c.end(), *it)
.
Обратите внимание, что чаще всего ожидается вызов emplace()
контейнера последовательности, такого как vector
, а не map
, поскольку emplace()
последнего не обязательно принимает итератор в качестве первого аргумента. Однако, поскольку map::emplace()
является неограниченной функцией, она все равно вызывается и вызывает серьезную ошибку.
Обходной путь — использовать views::common
для преобразования объединенного диапазона в common_range
, чтобы map
можно было создать с помощью классического конструктора map(InputIt first, InputIt last)
.
auto c = std::views::iota(1, 5)
| std::views::transform([](int const v){
return std::views::iota(1, 3)
| std::views::transform([v](int const w){
return std::make_pair(v, std::format("[{}/{}]", v, w));
});
})
| std::views::join
| std::views::common // no need for libc++
| std::ranges::to<std::map>();
common
это был деликатный вопрос 👍🏻