Output iterator's value_type

后端 未结 2 965
旧巷少年郎
旧巷少年郎 2020-12-31 00:15

The STL commonly defines an output iterator like so:

template
class insert_iterator
: public iterator

        
相关标签:
2条回答
  • 2020-12-31 00:55

    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.

    0 讨论(0)
  • 2020-12-31 00:57

    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.

    0 讨论(0)
提交回复
热议问题