Я использую 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это был деликатный вопрос 👍🏻