Преобразование с использованием диапазона-v3

Я пытаюсь использовать код ниже, используя диапазоны, но он не работает.

// Code
std::map<int, std::string> m{ {1,"foo"},{42,"bar"},{7,"baz"} };
std::vector<int> keys;

// without using ranges
std::transform(begin(m), end(m), std::back_inserter(keys), [](auto val)
{
    return val.first;
});

который работает нормально. Но,

// with using ranges
ranges::transform(m,std::back_inserter(keys), [](auto val)
{
    return val.first;
});

он не работает с диапазонами??

Я использую MSVC 2017 15.9.14.


person Ankit Thakar    schedule 08.08.2019    source источник


Ответы (1)


Range-v3 не поддерживает std::back_insert_iterator, поскольку он не соответствует концепции библиотеки Iterator, см. эта проблема. Как указано в обсуждении, это должно быть исправлено в C++20.

Вы можете исправить это либо

keys.resize(3);

ranges::transform(m, keys.begin(), [](auto val) { return val.first; });

или, на мой взгляд, предпочтительнее (как можно сделать keys const):

const std::vector<int> keys = m |
    ranges::view::transform([](auto val){ return val.first; });

В качестве примечания рассмотрите возможность передачи лямбда-параметра как ссылки с уточнением const, чтобы избежать ненужных копий.

person lubgr    schedule 08.08.2019
comment
Можно еще короче: m | view::keys - person Barry; 08.08.2019
comment
Спасибо за ответ @lubgr: - Это мне очень помогло. - person Ankit Thakar; 08.08.2019
comment
Я также могу написать как const auto keys = m | ranges::view::transform([](auto val){ return val.first; }); - person Ankit Thakar; 08.08.2019
comment
Неявное преобразование представлений в контейнеры устарело. Вы также должны передать его через ranges::to_vector. - person sv90; 12.08.2019
comment
@ sv90 О, интересно, почему это устарело? - person lubgr; 12.08.2019
comment
@lubgr Это коммит, который осуждает его. Объяснений нет. - person sv90; 12.08.2019