Предположим, что в С++ есть функция шаблона, которая выполняет некоторую полезную работу, но также выводит последовательность значений через выходной итератор. Теперь предположим, что эта последовательность значений иногда интересна, но в других это не полезно. Есть ли готовый к использованию класс итератора в 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) он не имеет ненужной внутренней переменной состояния.