21

在我的项目中,我想将流拆分为某种给定类型的值,因此我将模板函数实现为

template <typename TElem, typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    TElem elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

我认为这很尴尬,因为我必须TElem在调用它时明确给出类型。例如,我必须写:

std::vector<int> v;
SplitSpace<int>(std::cin, back_inserter(v));
// I want to it to be   SplitSpace(std::cin, back_inserter(v)); 

我试图从(模板)迭代器中获取值类型,std::iterator_traits并按如下方式使用:

template <typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    typename std::iterator_traits<TOutputIter>::value_type elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

但是,上述代码不适用于back_insert_iterator. back_insert_iterator/front_insert_iterator/insert_iterator我检查了命名空间中的源代码,std发现value_type/difference_type/pointer/reference都是void.

我想知道为什么这些类型都是void,有什么考虑吗?另一个问题是,是否可以在SplitSpace调用时不显式给出元素类型来实现该函数?谢谢。

4

4 回答 4

7

value_type在 OutputIterators 的情况下没有多大意义,因为输出迭代器不能访问任何值,更重要的是它可以接受广泛的值类型。

OutputIterator 的唯一要求it是它必须支持表达式*it = o whereo是某个类型的值,该值位于可写入 i 的特定迭代器类型的类型集中(第 24.2.1 节)。这意味着输出迭代器可以潜在地接受广泛的类型:例如,它可以返回一个为各种类型operator*重载的代理对象;在这种情况下operator=应该是什么?value_type

例如,考虑以下输出迭代器:

struct SwallowOutputIterator : 
    public std::iterator<output_iterator_tag, void, void, void, void>
{
    struct proxy // swallows anything
    {
        template <typename T>
        void operator=(const T &) {}
    };

    proxy operator*() 
    {
        return proxy();
    }

    // increment operators
};

这里没有明智的选择value_type

相同的推理适用于pointerreference_typedifference_type未定义,因为您无法计算两个输出迭代器之间的距离,因为它们是单程的。

注意:标准明确指出,insert_iterator它的兄弟姐妹必须继承自iterator<output_iterator_tag, void, void, void, void>,所以这不是你的实现的特点。

于 2013-04-23T10:05:23.427 回答
3

正如 Luc 在评论中提到的,您可以使用标准库轻松完成您想要做的事情:

std::vector<int> v;
std::copy( std::istream_iterator( std::cin )
         , std::istream_iterator()
         , std::back_inserter( v ) );
于 2013-04-23T09:51:41.910 回答
3

如果您只是在寻找一种避免指定TElem模板参数的方法,您可以使用这种方法:

template <typename TOutputIter>
TOutputIter SplitSpace(std::istream& IS, TOutputIter result)
{
    typedef typename TOutputIter::container_type::value_type TElem;

    TElem elem;
    while (IS >> elem)
    {
        *result = elem;
        ++result;
    }
    return result;
}

...当然,根据您假装使用的 TOutputIter 类型,您不应该使用这种方法。

于 2013-04-23T10:17:01.630 回答
2

AFAIK, you should be able to obtain the container_type from the iterator, from which you should be able to obtain a value_type. You probably want to specialize for a pair at some point. This should answer part two, as for part one; not sure...

于 2013-04-23T09:36:38.497 回答