输出迭代器的 value_type

发布于 2024-08-28 16:02:00 字数 1143 浏览 3 评论 0原文

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

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

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜灵血窟げ 2024-09-04 16:02:00

迭代器的实际值类型很可能是迭代器本身。 operator* 可以轻松地返回对 *this 的引用,因为真正的工作是由赋值运算符完成的。您可能会发现 *it = x;it = x; 对于输出迭代器具有完全相同的效果(我想可能会采取特殊措施来防止后者编译)。

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

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

我想这只是输出迭代器概念的限制:它们是“滥用”运算符重载的对象,以便看起来像指针,但实际上正在发生完全不同的事情。

不过你的问题很有趣。如果您想支持任何容器,那么相关的输出迭代器可能是 std::insert_iteratorstd::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';
}

它仍然只能让您走到这一步。我想人们可以更进一步,所以它也可以管理,比如说,std::ostream_iterator,但在某些时候它会变得如此复杂,以至于需要上帝来破译错误消息,如果出现问题。

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.

如此安好 2024-09-04 16:02:00

迭代器的 value_type 的目的是定义取消引用该迭代器时返回的类型。对于输出迭代器,解引用运算符的唯一合法用途是与赋值运算符结合使用——以 *output_iterator = value 的形式。取消引用输出迭代器时返回的类型不一定与可通过输出迭代器存储的类型有任何直接关系。唯一需要的关系是有某种方法将后一种类型分配给前一种类型。

此外,输出迭代器可以存储多种类型的值,并且这些类型之间不必有任何关系。以丢弃需要输出迭代器的函数的输出null_output_iterator为例>。该迭代器可以接受存储任何类型的值。

The purpose of the value_type of an iterator is to define the type that is returned when that iterator is dereferenced. For output iterators, the only legitimate use of the dereference operator is when it is used in conjunction with the assignment operator--in the form of *output_iterator = value. The type that is returned when dereferencing an output iterator does not necessarily have any direct relationship with the types that can be stored via the output iterator. The only needed relationship is that there be some way of assigning the latter types to the former type.

Moreover, the output iterator can store values of multiple types, and these types do not have to have any relationship with one another. Take for example the null_output_iterator described in Discarding the output of a function that needs an output iterator. That iterator can accept for storage any type of value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文