2

次のような 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ため、未定義の動作が発生します。iscreateRange

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)と、右辺値参照を a への入力として使用できないことを示す静的アサートが表示されます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ただし、が解放されるため、未定義の動作が発生します。これを回避できた唯一の方法は、valuesaを作成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としても、範囲とループの混合メタファーも洗練されていないと思います。

4

1 に答える 1