Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::back_inserter needs const_reference on older GCC. Why?

I am currently looking at some code that can be compiled on newer versions of GCC but not on older ones. In my case I am using a std::back_inserter to std::copy some data from one data structure to a custom data structure. If I forget the typedef value_type & const_reference typedef in this custom data structure however, this will not compile on GCC 4.4. The same code compiles and runs just fine on GCC 4.5.

What is the difference in between these two compiler versions, that makes the code compile on one version but not on the other. I would guess it has something to do with the implementation of C++11 which was much less complete in GCC 4.4. Probably something with decltype or another new C++11 keyword, I would guess.

Also is this code correct, if I use the std::back_inserter without defining the const_reference type? I usually thought that one has to implement the full set of typedefs (value_type, reference, const_reference etc) in order to be compatible with the STL-algorithms library? Or can I safely assume that if my code compiles in this case I am not invoking anything dangerous (e.g. move semantics, which would destroy my other datastructure).

like image 441
LiKao Avatar asked Nov 10 '11 14:11

LiKao


2 Answers

The standard (1998) says that std::back_insert_iterator needs Container::const_reference. In "24.4.2.1 Template class back_insert_iterator", [lib.back.insert.iterator], it says:

back_insert_iterator<Container>&
operator=(typename Container::const_reference value);

The 2011 standard only wants Container::value_type,

back_insert_iterator<Container>&
operator=(const typename Container::value_type& value);
back_insert_iterator<Container>&
operator=(typename Container::value_type&& value);

So, to be compatible with both versions of the C++ standard, define both value_type and const_reference_type.

In both GCC 4.4.6 and 4.5.1, the definition of operator= is identical (libstdc++-v3/include/bits/stl_iterator.h):

  back_insert_iterator&
  operator=(typename _Container::const_reference __value)
  {
    container->push_back(__value);
    return *this;
  }

and I get the same error with both compilers, perhaps you'll need to double check if you're using the correct compiler versions.

like image 75
chill Avatar answered Oct 23 '22 09:10

chill


The reason that you need const_reference defined for your data-structure is because the assignment operator in GCC 4.4 for an lvalue argument type in the std::back_insert_iterator class is defined as:

template<class Container>
back_insert_iterator<Container>& 
back_insert_iterator<Container>::operator= 
                  (typename Container::const_reference value);

Thus const_reference needs to be a resolvable identifier in your class-type in to properly instantiate the assignment operator in the std::back_insert_iterator class template.

In GCC 4.5, this definition of the assignment operator for lvalue arguments has been changed to

template<class Container>
back_insert_iterator<Container>&
back_insert_iterator<Container>::operator=
                 (const typename Container::value_type& value);

in order to support the new C++11 specification. Since your code compiles correctly with GCC 4.5, I'm assuming you must have value_type properly defined for your data-structure.

like image 34
Jason Avatar answered Oct 23 '22 09:10

Jason