Отбрасывание вывода функции, для которой требуется итератор вывода

Предположим, что в С++ есть функция шаблона, которая выполняет некоторую полезную работу, но также выводит последовательность значений через выходной итератор. Теперь предположим, что эта последовательность значений иногда интересна, но в других это не полезно. Есть ли готовый к использованию класс итератора в STL, который может быть создан и передан функции, и будет игнорировать любые значения, которые функция пытается назначить выходному итератору? Чтобы по-другому отправить все данные в/dev/null?

Ответ 1

STL не предоставляет такой итератор. Но вы сами могли бы его закодировать (протестировали этот код):

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) { 
        return *this;
    }

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

Он не нуждается в каких-либо данных, используя себя в результате operator*. Результат *it = x; не используется в требованиях выходного итератора, поэтому мы можем дать ему тип возврата void.


Изменить: расскажите, как работает этот operator*. Стандарт говорит в 24.1.2/1 о требованиях выходного итератора, который в обоих случаях:

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

То, что результат этих выражений не используется. Что делает эту работу:

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=`. 

Теперь нам не нужно иметь никаких данных, которые мы возвращаем в operator*: мы просто используем сам итератор. Обратите внимание, что шаблонный оператор = не перезаписывает оператор присваивания встроенной копии. Он по-прежнему предоставляется.

Ответ 2

Нетрудно написать один.

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

Я не тестировал это, и, вероятно, что-то важное отсутствует, но я думаю, что это идея.

Ответ 3

У вас есть Boost? Если это так, вы можете использовать function_output_iterator, обернув пустую функцию.

Это не идеальный, хотя. Какой бы итератор вы ни использовали, все равно нужно создать экземпляр value_type для возврата в operator *, даже если он затем отбрасывает его.

Ответ 4

Я основывался на std:: back_insert_iterator, но без контейнера:

#include <iterator>

template<typename T>
class NullOutputIter
    : public std::iterator<std::output_iterator_tag,void,void,void,void>
{
public:
    NullOutputIter &operator=(const T &) { return *this; }
    NullOutputIter &operator*() { return *this; }
    NullOutputIter &operator++() { return *this; }
    NullOutputIter operator++(int) { return *this; }
};

Это похоже на ответ Йоханнеса, но без шаблона operator=, который принимает все. Мне нравится сильная печать; Я хочу, чтобы *it = wrong_type_thing была ошибкой времени компиляции. Также используется void для различных параметров шаблона для std::iterator, как итераторы вывода в стандартной библиотеке.

Это также похоже на решение Mark, но (a) он правильно наследует от std::iterator и (b) он не имеет ненужной внутренней переменной состояния.