C++11-related compilation error with g++ 4.6 and boost::unordered_map

boost, c++, c++11, gcc, stl

Solution

The copy-assignment operator of `boost::unordered_map` is declared as:

unordered_map& operator=(unordered_map &t)

which in turn causes (C++98 12.8 [#10]) the implicit copy-assignment operator of `SomeStruct` to be declared as:

SomeStruct &operator= (SomeStruct &);

Adding an explicit copy-assignment operator

SomeStruct &operator= (const SomeStruct &x) { intMap = x.intMap; return *this; }

solves the issue, and it works by invoking a different overload of `unordered_map::operator=`.

This issue is fixed in Boost 1.52. which declares the operator as:

unordered_map& operator=(unordered_map const& x);

Problem

I have some piece of C++ code that fails with a compilation error unless it is run in C++11 mode, but I can't figure out why that would be the case as the code does not (explicitly) use C++11 features: ``` #include <vector> #include <map> #include <boost/unordered_map.hpp> struct SomeStruct { boost::unordered_map<int, int> intMap; }; int main(int argc, const char* argv[]) { std::vector<SomeStruct> vals; vals.resize(100); } ``` When compiling this on an Ubuntu 12.04 64bit machine with gcc 4.6.3-1ubuntu5 and boost 1.48: ``` g++ test.cpp ``` then I get this compilation error: ``` In file included from /usr/include/c++/4.6/vector:61:0, from test.cpp:1: /usr/include/c++/4.6/bits/stl_algobase.h: In function 'typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), void>::__type std::__fill_a(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = SomeStruct*, _Tp = SomeStruct, typename __gnu_cxx::__enable_if<(! std::__is_scalar<_Tp>::__value), void>::__type = void]': /usr/include/c++/4.6/bits/stl_algobase.h:722:7: instantiated from 'void std::fill(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = SomeStruct*, _Tp = SomeStruct]' /usr/include/c++/4.6/bits/vector.tcc:397:5: instantiated from 'void std::vector<_Tp, _Alloc>::_M_fill_insert(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<SomeStruct*, std::vector<SomeStruct> >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = SomeStruct*, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]' /usr/include/c++/4.6/bits/stl_vector.h:944:9: instantiated from 'void std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<SomeStruct*, std::vector<SomeStruct> >, typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer = SomeStruct*, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]' /usr/include/c++/4.6/bits/stl_vector.h:632:4: instantiated from 'void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type, std::vector<_Tp, _Alloc>::value_type) [with _Tp = SomeStruct, _Alloc = std::allocator<SomeStruct>, std::vector<_Tp, _Alloc>::size_type = long unsigned int, std::vector<_Tp, _Alloc>::value_type = SomeStruct]' test.cpp:12:18: instantiated from here /usr/include/c++/4.6/bits/stl_algobase.h:676:2: error: no match for 'operator=' in '* __first = __value' /usr/include/c++/4.6/bits/stl_algobase.h:676:2: note: candidate is: test.cpp:5:8: note: SomeStruct& SomeStruct::operator=(SomeStruct&) test.cpp:5:8: note: no known conversion for argument 1 from 'const SomeStruct' to 'SomeStruct&' ``` This compiles fine when enabling C++11 support in gcc: ``` g++ -std=c++0x test.cpp ``` Could somebody explain why this only works in C++11 mode ? Edit: Steps to reproduce using Vagrant: ``` vagrant init precise64 vagrant up vagrant ssh sudo apt-get install -y build-essential libboost1.48-all-dev echo "#include <vector> #include <map> #include <boost/unordered_map.hpp> struct SomeStruct { boost::unordered_map<int, int> intMap; }; int main(int argc, const char* argv[]) { std::vector<SomeStruct> vals; vals.resize(100); }" > test.cpp g++ test.cpp ```

Original source