c++stdmapc++23range-based-loop

How can I iterate a flat_map in a range-based 'for' loop, updating values?


It is easy to iterate std::map and update values:

#include <iostream>
#include <map>

int main() {
    std::map<int, int> m;
    m[1] = 2;
    m[2] = 4;
    for (auto &[k, v] : m) {
        v++; // <<< here
    }
    for (auto [k, v] : m) {
        std::cout << k << ' ' << v << '\n';
    }
    return 0;
}

But std::flat_map in the same situation gives a compilation error:

#include <iostream>
#include <flat_map>

int main() {
    std::flat_map<int, int> m;
    m[1] = 2;
    m[2] = 4;
    for (auto &[k, v] : m) {
        v++;
    }
    for (auto [k, v] : m) {
        std::cout << k << ' ' << v << '\n';
    }
    return 0;
}

The compiler says:

2.cpp: In function 'int main()':
2.cpp:8:25: error: cannot bind non-const lvalue reference of type 'std::pair<const int&, int&>&' to an rvalue of type 'std::_Flat_map_impl<int, int, std::less<int>, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >, false>::_Iterator<false>::reference' {aka 'std::pair<const int&, int&>'}
    8 |     for (auto &[k, v] : m) {
      |                         ^

The only way to update the values I found was using const_cast, but it looks disgusting:

#include <iostream>
#include <flat_map>

int main() {
    std::flat_map<int, int> m;
    m[1] = 2;
    m[2] = 4;
    for (const auto &[k, v] : m) {
        (*const_cast<int*>(&v))++;
    }
    for (auto [k, v] : m) {
        std::cout << k << ' ' << v << '\n';
    }
    return 0;
}

What is the correct way to iterate std::flat_map updating values? I know I can do it using non-range-based for loop and/or iterators. But is it possible that the construct, added in the Standard 23, is not compatible with the range-based for loop?


Solution

  • auto && will match the const/volatile/ref state of each variable.

    for (auto &&[k, v] : m) {
        v++;
    }
    

    See it working