输出迭代器的value_type

wil*_*ell 22 c++ iterator stl

STL通常定义一个输出迭代器,如下所示:

template<class Cont>
class insert_iterator
: public iterator<output_iterator_tag,void,void,void,void> {
    // ...
Run Code Online (Sandbox Code Playgroud)

为什么输出迭代器定义value_typevoid算法知道它应该输出什么类型的值会很有用.

例如,一个将URL查询"key1=value1&key2=value2&key3=value3"转换为包含键值字符串元素的任何容器的函数.

template<typename Ch,typename Tr,typename Out>
void parse(const std::basic_string<Ch,Tr>& str, Out result)
{
    std::basic_string<Ch,Tr> key, value;
    // loop over str, parse into p ...
        *result = typename iterator_traits<Out>::value_type(key, value);
}
Run Code Online (Sandbox Code Playgroud)

这提示的SGI参考页面value_type是因为无法取消引用输出迭代器.但这不是唯一的用途value_type:我可能想要实例化一个以便将它分配给迭代器.

有什么替代方法可以用输出迭代器构造输出值?我考虑过两种方法:

  • 接受一个函数参数,该参数将返回正确类型的对象.我仍然想要一个不采用该函数对象参数的算法版本.
  • 要求输出容器保持pair<string,string>,或者从中可以转换的类型.我想知道如果没有这个要求我能做到,也许允许任何可以从两个构造的元素std::string.

Unc*_*ens 10

迭代器的实际值类型很可能是迭代器本身.operator*可能很容易只返回一个引用,*this因为实际工作是由赋值运算符完成的.你可能会发现,*it = x;it = x;具有正好与输出迭代器(我想可能采取的特别措施,以防止后者编译)相同的效果.

因此,定义实际价值类型同样无用.void另一方面,将其定义为可以防止以下错误:

 typename Iter::value_type v = *it; //useless with an output iterator if it compiled
Run Code Online (Sandbox Code Playgroud)

我想这只是输出迭代器概念的极限:它们是"滥用"运算符重载的对象,以便呈现指针式,而实际上完全不同的东西正在发生.

不过,你的问题很有意思.如果你想支持任何容器,那么有问题的输出迭代器可能是std::insert_iterator,std::front_insert_iteratorstd::back_insert_iterator.在这种情况下,您可以执行以下操作:

#include <iterator>
#include <vector>
#include <string>
#include <map>
#include <iostream>

//Iterator has value_type, use it
template <class T, class IterValue>
struct value_type
{
    typedef IterValue type;
};

//output iterator, use the container's value_type
template <class Container>
struct value_type<Container, void>
{
    typedef typename Container::value_type type;
};

template <class T, class Out>
void parse_aux(Out out)
{
    *out = typename value_type<T, typename Out::value_type>::type("a", "b");
}

template <template <class> class Out, class T>
void parse(Out<T> out)
{
    parse_aux<T>(out);
}

//variadic template in C++0x could take care of this and other overloads that might be needed
template <template <class, class> class Out, class T, class U>
void parse(Out<T, U> out)
{
    parse_aux<T>(out);
}

int main()
{
    std::vector<std::pair<std::string, std::string> > vec;
    parse(std::back_inserter(vec));
    std::cout << vec[0].first << ' ' << vec[0].second << '\n';

    std::map<std::string, std::string> map;
    parse(std::inserter(map, map.end()));
    std::cout << map["a"] << '\n';

    //just might also support normal iterators
    std::vector<std::pair<std::string, std::string> > vec2(1);
    parse(vec2.begin());
    std::cout << vec2[0].first << ' ' << vec2[0].second << '\n';
}
Run Code Online (Sandbox Code Playgroud)

它仍然只会让你这么远.我想人们可以更进一步,所以它也可以管理,比如说,std::ostream_iterator<printable_type>但是在某些时候它会变得如此复杂以至于如果出现问题就需要上帝来破译错误信息.