Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize const containers with generators in modern C++?

In order to avoid mutable containers / states I currently wonder what's the closest thing to construct a const STL container from some input, e.g.

const vector<int> input = {2, 13, 7, 1};

What I'd like to do is something like this:

const auto transformed = generate_from<vector<string>>(
    input.begin(), input.end(), to_string);

do_something(transformed);

While the approach you find the most would create a mutable object and modify it (what I'd like to avoid):

vector<string> bad_mutable_container;
for (const auto & elem : input) {
    bad_mutable_container.push_back(to_string(input[elem]));
};

do_something(bad_mutable_container);

C++11 and newer provide std::generate and std::generate_n but they operate on a mutable object, so they don't solve my problem:

vector<string> bad_mutable_container(input.size());
generate_n(bad_mutable_container.begin(), input.size(), [&input, n=0] () mutable {
    return to_string(input[n++]);
});

What you can do now is encapsulate that code in a function/lambda which gives you const-ness but also noisy boilerplate code:

const auto transformed = [&input] {
    vector<string> bad_mutable_container;
    for (const auto & elem : input) {
        bad_mutable_container.push_back(to_string(elem));
    };
    return bad_mutable_container;
} ();

do_something(transformed);

I've expected to find at least some constructor for e.g. std::vector which I can use like this:

const auto transformed = vector<string>(input.size(), [&input, n=0] () mutable {
    return to_string(input[n++]);
});

What would be the most modern C++ish approach to this today and why?

like image 490
frans Avatar asked Jun 19 '18 10:06

frans


1 Answers

  • With boost::transform_iterator, you may do:

    auto to_string_fun = [](const auto& e){ return std::to_string(e); };
    const std::vector output(boost::transform_iterator(input.begin(), to_string_fun),
                             boost::transform_iterator(input.end(), to_string_fun));
    

    Demo

  • With range-v3, you may do:

     const std::vector<std::string> output = input
         | ranges::view::transform([](int e){ return std::to_string(e); });
    

    Demo

like image 139
Jarod42 Avatar answered Oct 11 '22 01:10

Jarod42