输出迭代器的value_type [英] Output iterator's value_type

查看:260
本文介绍了输出迭代器的value_type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  template< class Cont> 
class insert_iterator
:public iterator< output_iterator_tag,void,void,void,void> {
// ...

为什么输出迭代器定义 value_type as void 对于算法来说,知道应输出什么类型的值是有用的。



例如,一个翻译网址查询的函数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&键,值;
//循环遍历str,解析为p ...
* result = typename iterator_traits< Out> :: value_type(key,value);
}

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



< 我考虑的两种方法:




  • 接受函数参数,返回正确类型的对象。我仍然希望有一个版本的算法,不采取该函数对象参数。

  • 要求输出容器保存 pair< string,string> ,或者一种类型可以转换。我想知道我是否可以没有这个要求,也许允许任何可以从两个 std :: string 构造的元素。


解决方案

迭代器的实际值类型可能是迭代器本身。 运算符* 可以很容易地返回对 * this 的引用,因为实际工作是由赋值运算符完成的。你可能会发现 * it = x; it = x; 对输出迭代器我想可能采取特殊措施,以防止后者编译)。



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

  typename Iter :: value_type v = * it; //无用的输出迭代器如果它编译

我想这只是输出迭代器:它们是滥用操作符重载的对象,以便出现指针式的,而实际上完全不同的东西正在进行。



你的问题很有趣,但。如果你想支持任何容器,那么所讨论的输出迭代器可能是 std :: insert_iterator std :: front_insert_iterator std :: back_insert_iterator 。在这种情况下,你可以做如下:

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

// Iterator有value_type,使用它
template< class T,class IterValue>
struct value_type
{
typedef IterValue type;
};

//输出迭代器,使用容器的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>类Out,类T>
void parse(Out< T> out)
{
parse_aux< T&
}

// C ++ 0x中的可变参数模板可以处理可能需要的这个和其他重载
template< template< class,class>类Out,类T,类U>
void parse(Out< T,U> out)
{
parse_aux< T&
}

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

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

//也可能支持正常的迭代器
std :: vector< std :: pair< std :: string,std :: string> > vec2(1);
parse(Vec2.begin());
std :: cout<< vec2 [0] .first < ''<< vec2 [0] .second<< '\\\
';
}

这只会让你这么远。我想可以进一步,所以它也可以管理,例如,一个 std :: ostream_iterator< printable_type> ,但在某些时候,它会变得如此复杂,一个神来破译错误信息,应该出错了。


The STL commonly defines an output iterator like so:

template<class Cont>
class insert_iterator
: public iterator<output_iterator_tag,void,void,void,void> {
    // ...

Why do output iterators define value_type as void? It would be useful for an algorithm to know what type of value it is supposed to output.

For example, a function that translates a URL query "key1=value1&key2=value2&key3=value3" into any container that holds key-value strings elements.

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

The SGI reference page of value_type hints this is because it's not possible to dereference an output iterator. But that's not the only use of value_type: I might want to instantiate one in order to assign it to the iterator.

What alternative approach is there for constructing a value to output with the output iterator? Two approaches I considered:

  • Accept a functor parameter that would return an object of the correct type. I still want to have a version of the algorithm that doesn't take that function object parameter though.
  • Require that the output container holds pair<string,string>, or else a type convertible from that. I wonder if I can do without this requirement, perhaps allow any element that can construct from two std::string s.

解决方案

The real value type of the iterator could well be the iterator itself. operator* may easily just return a reference to *this because the real work is done by the assignment operator. You may well find that *it = x; and it = x; have exactly the same effect with output iterators (I suppose special measures might be taken to prevent the latter from compiling).

As such, defining the real value type would be just as useless. Defining it as a void, on the other hand, can prevent errors like:

 typename Iter::value_type v = *it; //useless with an output iterator if it compiled

I suppose this is just the limit of the concept of output iterators: they are objects which "abuse" operator overloading, so as to appear pointerlike, whereas in reality something completely different is going on.

Your problem is interesting, though. If you want to support any container, then the output iterators in question would probably be std::insert_iterator, std::front_insert_iterator and std::back_insert_iterator. In this case you could do something like the following:

#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';
}

It would still only get you this far. I suppose one could take this further, so it can also manage, say, a std::ostream_iterator<printable_type>, but at some point it would get so complex that it takes a god to decipher the error messages, should something go wrong.

这篇关于输出迭代器的value_type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆