0

Why do I get a C2440 for the

for(box& b : uset)

Error C2440 'initializing': cannot convert from 'const box' to 'box &'

Error (active) E0433 qualifiers dropped in binding reference of type "box &" to initializer of type "const box"

class box
{
public:
    int i = 1;
    bool operator==(const box& other) const
    {
        return true;
    }
    bool operator!=(const box& other) const
    {
        return !(*this == other);
    }

};

namespace std {

    template<>
    struct hash<box>
    {
        size_t operator()(const box& boxObject) const
        {
            return boxObject.i;
        }
    };
}

int main()
{
    std::unordered_set<box> uset;
    for (box& b : uset)
    {

    }
    return 0;
}

I'm confused as if I make it a reference to const box then the problem goes away. If I swap unordered_set to a vector then it's not a problem. I'm not sure what is going on here. Can someone help explain it to me. Is this particular to associative containers? I see it also happen with std::set.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
friartuck
  • 2,954
  • 4
  • 33
  • 67

1 Answers1

7

All of the associative containers only provide const access to the key type so you can't change it and break the way the container access the elements. That means

decltype(*std::unordered_set<box>{}.begin())

gives you a const box&. You can't bind a non const reference to a const object as that would violate const correctness so the code fails to compile.

What you need is

for (box const& b : uset)
{

}

so you have a reference to a const box.

You don't have this problem with a vector since the vector does not care about the value of the elements. It access by index, not the value of a element so nothing can break by changing the value of the element.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402