1

In my code, I frequently have to create a new container from a previously transformed range. So far I have used a combination of boost::adaptors::transformed and boost::copy_range to do the job, thinking that the container's constructor should be able to preallocate the necessary memory. Unfortunately, I have noticed that boost::adaptors::transform returns a SinglePassRange and I'm not sure if the size of the range can be determined in constant time.

namespace boost {
    template <typename SeqT, typename Range>
    inline SeqT copy_range(const Range& r)
    {
        return SeqT(boost::begin(r), boost::end(r));
    }
}

auto ints = std::vector<int>{...};
auto strings = boost::copy_range<std::vector<std::string>>(
    boost::adaptors::transform(ints, [](auto val) { 
        return std::to_string(val); 
    }));

So my question is: What is the best generic way to construct a new container from a transformed range ideally as one expression?

maxj
  • 45
  • 4

2 Answers2

2

You can use boost::adaptors::transformed. The docs state that the input range MUST at least be SinlgePassRange, but also says:

  • Returned Range Category: The range category of rng.

SO if the input range is random-access the output range will be, too. This removes your worry.

sehe
  • 374,641
  • 47
  • 450
  • 633
-2

std::transform is the way to go in C++11 and above:

std::set<int> ints = {1,2,3,1};
std::vector<std::string> strings;
std::transform(ints.begin(), ints.end(), std::back_inserter(strings), [] (int i) {
    return std::to_string(i)});

Using this you can only apply transform to every element in the given range. If you also want to do some filtering, you can use std::copy_if. I recommend to study the header, it's full of gems.

EDIT: added back_inserter

AndreiM
  • 815
  • 9
  • 17
  • 1
    I think you missed to use a back_inserter for strings and even then, this wouldn't be the most efficient way as the size of strings isn't reserved and thus multiple heap allocations would take place. – maxj Jul 25 '18 at 08:03
  • what do you mean by multiple heap allocation? There should be one allocation per every element in the input container. – AndreiM Jul 25 '18 at 08:08
  • We mean that `strings.reserve(ints.size());` is missing. – Jarod42 Jul 25 '18 at 08:19
  • I was hoping to find a generic solution, which does the right thing for `vector` as well as `unordered_set`, `set`, etc. Moreover it requires three lines (including `reserve()`). – maxj Jul 25 '18 at 08:36