Я хочу вернуть диапазон из функции, представляющей представление коллекции STL, примерно так:
auto createRange() {
std::unordered_set<int> is = {1, 2, 3, 4, 5, 6};
return is | view::transform([](auto&& i) {
return i;
});
}
Однако view::transform
не становится владельцем is
, поэтому, когда я запускаю это, возникает неопределенное поведение, потому что is
освобождается при выходе createRange
.
int main(int argc, char* argv[]) {
auto rng = createRange();
ranges::for_each(rng, [](auto&& i) {
std::cout << std::to_string(i) << std::endl;
});
}
Если я попробую std::move(is)
в качестве входных данных, я получу статическое утверждение, указывающее, что я не могу использовать ссылки rvalue в качестве входных данных для view
. Есть ли способ гарантировать, что представление станет владельцем коллекции?
Изменить: дополнительная информация
Хочу добавить уточняющую информацию. У меня есть поток данных data
, представление которого преобразует данные в структуру Foo
, которая выглядит примерно так:
struct Foo {
std::string name;
std::unordered_set<int> values;
}
// Take the input stream and turn it into a range of Foos
auto foos = data | asFoo();
Что я хочу сделать, так это создать диапазон std::pair<std::string, int>
, распределив имя по значениям. Моя наивная попытка выглядит примерно так:
auto result = data | asFoo() | view::transform([](auto&& foo) {
const auto& name = foo.name;
const auto& values = foo.values;
return values | view::transform([name](auto&& value) {
return std::make_pair(name, value);
}
}) | view::join;
Однако это приводит к неопределенному поведению, поскольку values
освобождается. Единственный способ обойти это — сделать values
std::shared_ptr
и зафиксировать его в лямбда-выражении, переданном view::transform
, чтобы сохранить его время жизни. Это кажется неэлегантным решением.
Я думаю, что я ищу представление, которое будет владеть исходной коллекцией, но не похоже, что в range-v3 это есть.
В качестве альтернативы я мог бы просто создать распределенную версию, используя старый добрый цикл for, но, похоже, он не работает с view::join
:
auto result = data | asFoo() | view::transform([](auto&& foo) {
const auto& name = foo.name;
const auto& values = foo.values;
std::vector<std::pair<std::string, std::string>> distributedValues;
for (const auto& value : values) {
distributedValues.emplace_back(name, value);
}
return distributedValues;
}) | view::join;
Даже если это работало с view::join
, я также думаю, что смешанная метафора диапазонов и циклов также неэлегантна.
is
, чтобы он содержал преобразованные данные и возвращал их напрямую? Зачем тебе вообще здесь вид? - person ildjarn   schedule 15.05.2018