How to get the value type from an output iterator?

安稳与你 提交于 2019-12-05 14:30:01

问题


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:

  1. getFirstElem(MyContainer const&, void*): Outputs the first element of the container.
  2. 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).


回答1:


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:

1. Pass the container

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

2. Pass an extra template parameter

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;
...



回答2:


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));
    }
}



回答3:


There are different ways to solve this, I did it like this:

template <class T>
std::enable_if_t<!std::is_same_v<typename T::container_type::value_type, void>, size_t> read(T first, size_t count)
{
    typedef typename T::container_type::value_type value_type;

I have another one for the usual iterator.



来源:https://stackoverflow.com/questions/25118328/how-to-get-the-value-type-from-an-output-iterator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!