tags:

views:

222

answers:

3

Suppose there´s a template function in C++ that does some useful work but also outputs a sequence of values via an output iterator. Now suppose that that sequence of values sometimes is interesting, but at others is not useful. Is there a ready-to-use iterator class in the STL that can be instantiated and passed to the function and will ignore any values the function tries to assign to the output iterator? To put in another way, send all data to /dev/null?

+2  A: 

Do you have Boost available? If so you could use a function_output_iterator wrapping an empty function.

It's not ideal though. Whatever iterator you use will still need to create an instance of the value_type for return in operator*, even if it then throws it away.

Alastair
+3  A: 

It isn't hard to write one.

template<typename T>
class NullOutputIterator
{
public:
    NullOutputIterator() {}
    NullOutputIterator& operator++() { return *this; }
    NullOutputIterator& operator++(int) { return *this; }
    T& operator*() { return m; }
    T* operator->() { return &m; }
private:
    T m;
};

I haven't tested this, and there's probably something important missing, but I think this is the idea.

Mark Ransom
The idea is good, but I don´t think you need:T* operator->() { return }And you should derive from stl::output_iteratorWith this implementation a copy of T is executed at each assignment through the out iterator. Is there anyway to avoid that?
David Reis
+8  A: 

The STL does not provide such an iterator. But you could code it yourself (tested that code):

struct null_output_iterator : 
    std::iterator< std::output_iterator_tag,
                   null_output_iterator > {
    /* no-op assignment */
    template<typename T>
    void operator=(T const&) { }

    null_output_iterator & operator++() { 
        return *this; 
    }

    null_output_iterator operator++(int) { 
        null_output_iterator it(*this); 
        ++*this;
        return it;
    }

    null_output_iterator & operator*() { return *this; }
};

It doesn't need any data by using itself as the result of operator*. The result of *it = x; is not used in the output iterator requirements, so we can give it a return type of void.


Edit: Let's go into how this operator* works. The Standard says in 24.1.2/1 about the requirements of an output iterator that in both these cases:

*it = t;
*it++ = t;

That the result of those expressions is not used. That's what makes this work:

null_output_iterator it;
*it; // returns a null_output_iterator& per definition of the `operator*`.
*it = some_value; // returns void per definition of the templated `operator=`.

Now we don't need to have any data that we return in operator*: We just use the iterator itself. Note that the templated operator= does not overwrite the builtin copy assignment operator. It's still provided.

Johannes Schaub - litb
Could you better explain the operator*?
David Reis
It's used in combination with the templated operator=. Tricky, I'd use a nested helper class dev_null.Also, I'd let operator++(int) return *this immediately. This version is inefficient.
MSalters
msalters, the operational semantics state a new object is returned :)
Johannes Schaub - litb