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

  • A+

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?


  • 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)); 


  • With range-v3, you may do:

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



:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: