Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting all values in a std::map

Tags:

c++

stl

How to set all the values in a std::map to the same value, without using a loop iterating over each value?

like image 384
Will Avatar asked Sep 26 '08 12:09

Will


1 Answers

Using a loop is by far the simplest method. In fact, it’s a one-liner:[C++17]

for (auto& [_, v] : mymap) v = value;

Unfortunately C++ algorithm support for associative containers isn’t great pre-C++20. As a consequence, we can’t directly use std::fill.

To use them anyway (pre-C++20), we need to write adapters — in the case of std::fill, an iterator adapter. Here’s a minimally viable (but not really conforming) implementation to illustrate how much effort this is. I do not advise using it as-is. Use a library (such as Boost.Iterator) for a more general, production-strength implementation.

template <typename M>
struct value_iter : std::iterator<std::bidirectional_iterator_tag, typename M::mapped_type> {
    using base_type = std::iterator<std::bidirectional_iterator_tag, typename M::mapped_type>;
    using underlying = typename M::iterator;
    using typename base_type::value_type;
    using typename base_type::reference;

    value_iter(underlying i) : i(i) {}

    value_iter& operator++() {
        ++i;
        return *this;
    }

    value_iter operator++(int) {
        auto copy = *this;
        i++;
        return copy;
    }

    reference operator*() { return i->second; }

    bool operator ==(value_iter other) const { return i == other.i; }
    bool operator !=(value_iter other) const { return i != other.i; }

private:
    underlying i;
};

template <typename M>
auto value_begin(M& map) { return value_iter<M>(map.begin()); }

template <typename M>
auto value_end(M& map) { return value_iter<M>(map.end()); }

With this, we can use std::fill:

std::fill(value_begin(mymap), value_end(mymap), value);
like image 122
Konrad Rudolph Avatar answered Sep 29 '22 10:09

Konrad Rudolph