Предположим, что в C++ есть функция шаблона, которая выполняет некоторую полезную работу, но также выводит последовательность значений через выходной итератор. Теперь предположим, что эта последовательность значений иногда интересна, но в других это не полезно. Есть ли готовый к использованию класс итератора в STL, который может быть создан и передан функции, и будет игнорировать любые значения, которые функция пытается назначить выходному итератору? Чтобы по-другому отправить все данные в/dev/null?Отказ от вывода функции, для которой нужен выходной итератор
ответ
У вас есть Boost? Если это так, вы можете использовать function_output_iterator, обертывая пустую функцию.
Это не идеальный вариант. Независимо от того, какой итератор вы используете, все равно нужно создать экземпляр value_type для возврата в operator *, даже если он затем отбросит его.
Нетрудно написать его.
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;
};
Я не проверял это, и, вероятно, что-то важное отсутствует, но я думаю, что это идея.
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*
: Мы просто использовать сам итератор. Обратите внимание, что шаблонный оператор = не перезаписывает оператор присваивания встроенной копии. Он по-прежнему предоставляется.
Не могли бы вы лучше объяснить оператора *? – 2008-12-03 01:21:01
Я основан на шахте 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; }
};
Это похоже на ответ Johannes, но без шаблона operator=
, который принимает любые. Мне нравится сильная печать; Я хочу, чтобы *it = wrong_type_thing
была ошибкой времени компиляции. Также это использует void
для различных параметров шаблона до std::iterator
, как итераторы вывода в стандартной библиотеке.
Это также похоже на решение Марка, но (а) оно правильно наследует от std::iterator
и (b) оно не имеет ненулевой переменной внутреннего состояния.
Идея хорошая, но я не думаю, что вам нужно: T * operator ->() {return & m; } И вы должны получить из stl :: output_iterator С этой реализацией копия T выполняется при каждом присваивании через итератор. Есть ли вообще избежать этого? – 2008-12-03 01:15:36