Определение основанного на прокси OutputIterator с точки зрения boost :: iterator_facade

Я написал этот код на C ++ 17 и ожидал, что он будет работать «из коробки».

class putc_iterator : public boost::iterator_facade<
putc_iterator,
void,
std::output_iterator_tag
>
{
friend class boost::iterator_core_access;

struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
auto dereference() const { return proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};

Я пытаюсь соответствовать поведению всех стандартных OutputIterators, устанавливая typedefs члена моего итератора value_type а также reference в void (так как эти типы не имеют смысла для итератора, чей operator* не возвращает ссылку).

Однако Буст жалуется:

In file included from prog.cc:2:
/opt/wandbox/boost-1.63.0/clang-head/include/boost/iterator/iterator_facade.hpp:333:50: error: cannot form a reference to 'void'
static result_type apply(Reference const & x)
^

Похоже, Boost пытается жестко кодировать сгенерированный operator*подпись как reference operator*() const, То есть, boost::iterator_facade мог вывести правильный тип возвращаемого значения operator*() просто передавая то, что было возвращено dereference(); но по какой-то причине это просто не подыгрывает.

Какое решение? Я не могу пройти proxy в качестве параметра шаблона базового класса, так как proxy еще не определено. Я мог вытащить proxy в пространство имен деталей:

namespace detail {
struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
}
class putc_iterator : public boost::iterator_facade<
putc_iterator,
void,
std::output_iterator_tag,
detail::proxy
>
{
friend class boost::iterator_core_access;

auto dereference() const { return detail::proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};

но это кажется неловким и определенно то, что «не должно быть необходимым».

Это ошибка в iterator_facade? Это особенность, а не ошибка? Если последнее, то как я предполагаемый использовать его для создания OutputIterators?

Кроме того, незначительный придирки: даже мой обход с пространством имен детализации «неправильный» в том смысле, что он делает std::is_same_v<putc_iterator::reference, detail::proxy> когда что я хочу (для паритета со стандартными итераторами) std::is_same_v<putc_iterator::reference, void>,

0

Решение

Boost Iterator Facade был хорош в то время, но сейчас он устарел, так как не очень гибок (он плохо сочетается с auto и с ссылками на r-значение, которые в принципе могут быть созданы путем разыменования итератора r-значения). Я не повторяю концепцию фасада, но она может быть обновлена ​​до C ++ 11.

Кроме того, теперь с C ++ 11 проще написать итератор с нуля.

Во всяком случае, если вам нужно определить reference просто чтобы соответствовать аргументам, которые будут переданы, (и если вы обещаете не использовать его), вы можете использовать void* вместо void, (Или возможно для использования последовательности proxy& и определить его вне класса).

class putc_iterator : public boost::iterator_facade<
putc_iterator,
void*,
std::output_iterator_tag
>
{
friend class boost::iterator_core_access;

struct proxy {
void operator= (char ch) { putc(ch, stdout); }
};
auto dereference() const { return proxy{}; }
void increment() {}
bool equal(const putc_iterator&) const { return false; }
};
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]