STL通常定义一个输出迭代器,如下所示:
template<class Cont>
class insert_iterator
: public iterator<output_iterator_tag,void,void,void,void> {
// ...
为什么输出迭代器将value_type
定义为void
?算法知道它应该输出什么类型的值会很有用。
例如,一个将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);
}
SGI reference page of value_type
提示这是因为无法取消引用输出迭代器。但这不是value_type
的唯一用途:我可能想要实例化一个以便将它分配给迭代器。
使用输出迭代器构造输出值的替代方法是什么?我考虑过两种方法:
pair<string,string>
,否则可以转换为该类型的类型。我想知道如果没有这个要求我是否可以做,也许允许任何可以从两个std::string
s构建的元素。答案 0 :(得分:10)
迭代器的实际值类型很可能是迭代器本身。 operator*
可能很容易只返回对*this
的引用,因为实际工作是由赋值运算符完成的。您可能会发现*it = x;
和it = x;
与输出迭代器具有完全相同的效果(我想可能会采取特殊措施来防止后者编译)。
因此,定义实际价值类型同样无用。另一方面,将其定义为void
可以防止出现以下错误:
typename Iter::value_type v = *it; //useless with an output iterator if it compiled
我认为这只是输出迭代器概念的极限:它们是“滥用”运算符重载的对象,因此出现指针式,而实际上完全不同的东西正在发生。
但你的问题很有意思。如果要支持任何容器,则有问题的输出迭代器可能是std::insert_iterator
,std::front_insert_iterator
和std::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';
}
它仍然只会让你这么远。我想人们可以更进一步,所以它也可以管理一个std::ostream_iterator<printable_type>
,但在某些时候它会变得如此复杂,以至于如果出现问题,需要上帝解密错误消息。
答案 1 :(得分:2)
迭代器的value_type的目的是定义取消引用迭代器时返回的类型。对于输出迭代器,解除引用运算符的唯一合法用途是当它与赋值运算符一起使用时 - 以*output_iterator = value
的形式。取消引用输出迭代器时返回的类型不一定与可以通过输出迭代器存储的类型有任何直接关系。唯一需要的关系是有一些方法可以将后一种类型分配给前一种类型。
此外,输出迭代器可以存储多种类型的值,并且这些类型不必彼此具有任何关系。以Discarding the output of a function that needs an output iterator中描述的null_output_iterator
为例。迭代器可以接受存储任何类型的值。