Problems with nesting boost::container::small_vector and C++98

Hi, first the used versions: boost 1.63.0 gcc 5.4.0 20160609 Ubuntu 16.04.1 the example I've problems with is: #include <map> #include <boost/container/small_vector.hpp> using boost::container::small_vector; typedef std::pair<int, small_vector<float, 8> > mypair; typedef std::map<int, mypair> mymap; typedef std::map<int, small_vector<mypair, 8> > mymap2; typedef std::map<int, small_vector<small_vector<float, 8>, 8> > mymap3; int main() { mymap m; mypair& sv = m[0]; mymap2 m2; small_vector<mypair, 8>& sv2 = m2[0]; mymap3 m3; small_vector<small_vector<float, 8>, 8>& sv3 = m3[0]; } I can compile it without errors with 'g++ -std=c++11', but without '-std=c++11' I'm getting an error for the 'operator[]' on mymap2: dan@octa ~> g++ -Iboost_1_63_0/ small_vector_test.cpp In file included from boost_1_63_0/boost/container/small_vector.hpp:27:0, from small_vector_test.cpp:2: boost_1_63_0/boost/container/vector.hpp: In instantiation of ‘void boost::container::vector<T, Allocator>::assign(FwdIt, FwdIt, typename boost::move_detail::disable_if_or<void, boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::move_detail::integral_constant<unsigned int, 0u> >, boost::move_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>, boost::container::container_detail::is_input_iterator<FwdIt> >::type*) [with FwdIt = boost::container::container_detail::vec_iterator<std::pair<int, boost::container::small_vector<float, 8ul> >*, true>; T = std::pair<int, boost::container::small_vector<float, 8ul> >; Allocator = boost::container::small_vector_allocator<boost::container::new_allocator<std::pair<int, boost::container::small_vector<float, 8ul> > > >; typename boost::move_detail::disable_if_or<void, boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::move_detail::integral_constant<unsigned int, 0u> >, boost::move_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>, boost::container::container_detail::is_input_iterator<FwdIt> >::type = void]’: boost_1_63_0/boost/container/small_vector.hpp:563:7: required from ‘boost::container::small_vector<T, N, Allocator>::small_vector(const boost::container::small_vector<T, N, Allocator>&) [with T = std::pair<int, boost::container::small_vector<float, 8ul> >; long unsigned int N = 8ul; Allocator = boost::container::new_allocator<std::pair<int, boost::container::small_vector<float, 8ul> > >]’ /usr/include/c++/5/bits/stl_pair.h:113:31: required from ‘std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = const int; _T2 = boost::container::small_vector<std::pair<int, boost::container::small_vector<float, 8ul> >, 8ul>]’ /usr/include/c++/5/bits/stl_map.h:487:23: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = boost::container::small_vector<std::pair<int, boost::container::small_vector<float, 8ul> >, 8ul>; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, boost::container::small_vector<std::pair<int, boost::container::small_vector<float, 8ul> >, 8ul> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = boost::container::small_vector<std::pair<int, boost::container::small_vector<float, 8ul> >, 8ul>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]’ small_vector_test.cpp:18:39: required from here boost_1_63_0/boost/container/vector.hpp:1261:15: error: binding ‘const std::pair<int, boost::container::small_vector<float, 8ul> >’ to reference of type ‘std::pair<int, boost::container::small_vector<float, 8ul> >&’ discards qualifiers *cur = *first; ^ In file included from /usr/include/c++/5/bits/stl_algobase.h:64:0, from /usr/include/c++/5/bits/stl_tree.h:63, from /usr/include/c++/5/map:60, from small_vector_test.cpp:1: /usr/include/c++/5/bits/stl_pair.h:96:12: note: initializing argument 1 of ‘std::pair<int, boost::container::small_vector<float, 8ul> >& std::pair<int, boost::container::small_vector<float, 8ul> >::operator=(std::pair<int, boost::container::small_vector<float, 8ul> >&)’ struct pair ^ Any ideas? Is 'boost:container::small_vector' supposed to work without C++11 support? Thanks! Greetings, Daniel

Hi,
typedef std::pair<int, small_vector<float, 8> > mypair;
If I'm replacing 'mypair' with 'mystruct': struct mystruct { mystruct& operator=(const mystruct& other) { i = other.i; sv = other.sv; return *this; } int i; small_vector<float, 8> sv; }; Then I can compile it without C++11 support, but I've to implement the 'operator=' by hand, otherwise I'm still getting a compile error: dan@octa ~> g++ -Iboost_1_63_0/ small_vector_test_2.cpp In file included from boost_1_63_0/boost/container/small_vector.hpp:27:0, from small_vector_test_2.cpp:2: boost_1_63_0/boost/container/vector.hpp: In instantiation of ‘void boost::container::vector<T, Allocator>::assign(FwdIt, FwdIt, typename boost::move_detail::disable_if_or<void, boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::move_detail::integral_constant<unsigned int, 0u> >, boost::move_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>, boost::container::container_detail::is_input_iterator<FwdIt> >::type*) [with FwdIt = boost::container::container_detail::vec_iterator<mystruct*, true>; T = mystruct; Allocator = boost::container::small_vector_allocator<boost::container::new_allocator<mystruct> >; typename boost::move_detail::disable_if_or<void, boost::move_detail::is_same<typename boost::container::container_detail::version<Allocator>::type, boost::move_detail::integral_constant<unsigned int, 0u> >, boost::move_detail::is_convertible<InIt, typename boost::container::allocator_traits<Allocator>::size_type>, boost::container::container_detail::is_input_iterator<FwdIt> >::type = void]’: boost_1_63_0/boost/container/small_vector.hpp:563:7: required from ‘boost::container::small_vector<T, N, Allocator>::small_vector(const boost::container::small_vector<T, N, Allocator>&) [with T = mystruct; long unsigned int N = 8ul; Allocator = boost::container::new_allocator<mystruct>]’ /usr/include/c++/5/bits/stl_pair.h:113:31: required from ‘std::pair<_T1, _T2>::pair(const _T1&, const _T2&) [with _T1 = const int; _T2 = boost::container::small_vector<mystruct, 8ul>]’ /usr/include/c++/5/bits/stl_map.h:487:23: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = int; _Tp = boost::container::small_vector<mystruct, 8ul>; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, boost::container::small_vector<mystruct, 8ul> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = boost::container::small_vector<mystruct, 8ul>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]’ small_vector_test_2.cpp:21:41: required from here boost_1_63_0/boost/container/vector.hpp:1261:15: error: binding ‘const mystruct’ to reference of type ‘mystruct&’ discards qualifiers *cur = *first; ^ small_vector_test_2.cpp:6:8: note: initializing argument 1 of ‘mystruct& mystruct::operator=(mystruct&)’ For whatever reasons the operator 'mystruct& mystruct::operator=(mystruct&)' is used, with a non const reference parameter, which can't work in this context. Looks like a bug? boost? gcc? Greetings, Daniel

Attached the source file with 'mypair' replaced by 'mystruct'.

On 31/12/2016 17:44, Daniel Trstenjak wrote:
Hi,
first the used versions: boost 1.63.0 gcc 5.4.0 20160609 Ubuntu 16.04.1
the example I've problems with is:
#include <map> #include <boost/container/small_vector.hpp>
using boost::container::small_vector;
typedef std::pair<int, small_vector<float, 8> > mypair;
typedef std::map<int, mypair> mymap; typedef std::map<int, small_vector<mypair, 8> > mymap2; typedef std::map<int, small_vector<small_vector<float, 8>, 8> > mymap3;
int main() { mymap m; mypair& sv = m[0];
mymap2 m2; small_vector<mypair, 8>& sv2 = m2[0];
mymap3 m3; small_vector<small_vector<float, 8>, 8>& sv3 = m3[0]; }
In C++98 std::pair copy constructor is implicitly declared. Since small_vector declares operator= taking a non-const reference (as that's how move semantics are emulated), then std::pair's operator= takes a non-const pair argument: http://en.cppreference.com/w/cpp/language/copy_assignment#Implicitly-declare... So the problem you are facing it's a limitation of the move emulation library. When you define your own class holding a small_vector, you have the same problem. When you explicitly declare operator= taking a const reference the problem is solved. See: http://www.boost.org/doc/libs/1_63_0/doc/html/move/emulation_limitations.htm... and http://www.boost.org/doc/libs/1_63_0/doc/html/container/known_issues.html#co... Best, Ion

On Sun, Jan 01, 2017 at 10:30:14PM +0100, Ion Gaztañaga wrote:
So the problem you are facing it's a limitation of the move emulation library.
Thank you for the info! It seems a bit unfortunate that the move emulation library breaks that easily. Greetings, Daniel
participants (2)
-
Daniel Trstenjak
-
Ion Gaztañaga