Let's say that I have a C container (e.g., MyContainer) with contained objects stored as void* pointers. The only way to iterate through the elements of this container is via two interface functions:
getFirstElem(MyContainer const&, void*): Outputs the first element of the container.getNextElem(MyContainer const&, void*): Outputs the next element of the container.I want to code a generic function that iterates through the elements of this C container via the interface functions mentioned above and copy their values into a C++ container (e.g. std::vector).
What I've done so far:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
  typename std::iterator_traits<OutputIterator>::value_type elem;
  if(getFirstElem(cont, &elem)) {
    do {
      *first = elem;
      ++first;
    } while(getNextElem(cont, &elem))    
  }
}
The above example works OK with normal iterators. However, it fails to compile with output iterators (e.g., copy_container(cont, std::back_inserter(myvector));).
The reason is that std::iterator_traits::value_type results in void in cases where the argument type is an output iterator.
Is there a way to make this generic function work for output iterators as well?
I know that in C++11 it could be done by using decltype (e.g., decltype(*first)), but I'm particularly interested in pre-C++11 solutions since I use an old C++ compiler (gcc v4.4.7).
You may use typetraits and specialization
template <typename IT>
struct it_value_type
{
    typedef typename std::iterator_traits<IT>::value_type elem;
};
template <typename Container>
struct it_value_type<std::back_insert_iterator<Container>>
{
    typedef typename Container::value_type elem;
};
template <typename Container>
struct it_value_type<std::front_insert_iterator<Container>>
{
    typedef typename Container::value_type elem;
};
And then you code becomes:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
    typename it_value_type<OutputIterator>::elem elem;
    if (getFirstElem(cont, &elem)) {
        do {
            *first = elem;
            ++first;
        } while (getNextElem(cont, &elem));
    }
}
                        As correctly observed, the value_type of an output iterator is void. So there not much to do apart from replacing this : 
typename std::iterator_traits<OutputIterator>::value_type elem;
with this
decltype(*first) elem;
(even though the Standard doesn't guarantee it'll work - a proxy might be returned by dereferencing an output iterator).
As you said no C++11 solution so a redesign might be needed. Here are some options:
Instead of an iterator to the first element, you could pass a reference to the container. It seems like all you want is a push_back.
template<template<typename,typename> class stlContainer>
void copy_container(
    MyMontainer const &cont, OutputIterator first) 
{ 
    // insertion in stlContainer
then all you need is a layer of traits to dispatch to the right implementation of insertion per container
The value type could be an extra template parameter.
template<typename value_type, typename OutputIterator>
void copy_container(MyMontainer const &cont, OutputIterator first) 
{
    value_type elem;
...
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With