Отбрасывание вывода функции, которой нужен выходной итератор - PullRequest
19 голосов
/ 03 декабря 2008

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

Ответы [ 4 ]

21 голосов
/ 03 декабря 2008

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*: мы просто используем сам итератор. Обратите внимание, что шаблонный оператор = не перезаписывает встроенный оператор присваивания копии. Это все еще предоставляется.

4 голосов
/ 03 декабря 2008

Не сложно написать один.

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 голосов
/ 03 декабря 2008

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

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

1 голос
/ 07 июня 2017

Я основал мой на 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, как итераторы вывода в стандартной библиотеке.

Это также похоже на решение Марка, но (а) оно должным образом наследует от std::iterator и (б) у него нет ненужной внутренней переменной состояния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...