如何从输出迭代器中获取值类型?

时间:2014-08-04 12:07:19

标签: c++ stl iterator c++03

让我们说我有一个C容器(例如,MyContainer),其中包含的对象存储为void*指针。迭代此容器元素的唯一方法是通过两个接口函数:

  1. getFirstElem(MyContainer const&, void*):输出容器的第一个元素。
  2. getNextElem(MyContainer const&, void*):输出容器的下一个元素。
  3. 我想编写一个泛型函数,它通过上面提到的接口函数遍历这个C容器的元素,并将它们的值复制到C ++容器中(例如std::vector)。

    到目前为止我做了什么:

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

    以上示例适用于普通迭代器。但是,它无法使用输出迭代器进行编译(例如,copy_container(cont, std::back_inserter(myvector));)。

    原因是std::iterator_traits::value_type在参数类型是输出迭代器的情况下导致void

    有没有办法让这个泛型函数也适用于输出迭代器?

    我知道在C ++ 11中可以使用decltype(例如decltype(*first))来完成,但我对C ++ 11之前的解决方案特别感兴趣,因为我使用旧的C ++编译器(gcc v4.4.7)。

3 个答案:

答案 0 :(得分:7)

正确观察,输出迭代器的value_typevoid。所以除了替换它之外别无选择:

typename std::iterator_traits<OutputIterator>::value_type elem;

用这个

decltype(*first) elem;

(即使标准不能保证它能够正常工作 - 也可以通过解除引用输出迭代器来返回代理)。

正如您所说,没有C ++ 11解决方案,因此可能需要进行重新设计。以下是一些选项:

1。传递容器

您可以将引用传递给容器,而不是第一个元素的迭代器。看起来你想要的只是一个push_back

template<template<typename,typename> class stlContainer>
void copy_container(
    MyMontainer const &cont, OutputIterator first) 
{ 
    // insertion in stlContainer

然后您需要的是一层特征,以便分配到每个容器的正确插入实现

2。传递额外的模板参数

值类型可以是额外的模板参数。

template<typename value_type, typename OutputIterator>
void copy_container(MyMontainer const &cont, OutputIterator first) 
{
    value_type elem;
...

答案 1 :(得分:3)

您可以使用typetraits和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;
};

然后您的代码变为:

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

答案 2 :(得分:0)

有不同的解决方法,我这样做:

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;

我有另一个用于通常的迭代器。