代码之家  ›  专栏  ›  技术社区  ›  wilhelmtell

输出迭代器的值类型

  •  21
  • wilhelmtell  · 技术社区  · 14 年前

    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 提示这是因为不可能取消对输出迭代器的引用。但这并不是 值类型 :我可能想实例化一个,以便将其分配给迭代器。

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

    • 接受将返回正确类型对象的函子参数。我仍然希望有一个算法的版本,不带函数对象参数。
    • 要求输出容器保存 pair<string,string> ,或者从中转换的类型。我想知道我是否可以不使用这个需求,或者允许任何可以从两个 std::string S.
    2 回复  |  直到 14 年前
        1
  •  10
  •   UncleBens    14 年前

    迭代器的真正值类型很可能是迭代器本身。 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> 但在某个时刻,它会变得如此复杂,以至于如果出了问题,上帝需要破译错误信息。

        2
  •  2
  •   Community Egal    7 年前

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

    此外,输出迭代器可以存储多个类型的值,这些类型不必彼此有任何关系。例如 null_output_iterator 描述于 Discarding the output of a function that needs an output iterator . 迭代器可以接受存储任何类型的值。