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

我试图通过将迭代器的成员 typedefs 设置为value_type并将reference设置为void来匹配所有标准输出迭代器的行为(因为这些类型对于operator*不返回引用的迭代器毫无意义)。

然而,Boost抱怨说:

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可以通过简单地传递dereference()返回的任何内容来推断出operator*()的正确返回类型;但出于某种原因,它只是不玩。

解决方案是什么?我无法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中的错误吗? 它是一个功能不是错误吗? 如果是后者,那么我应该如何使用它来创建输出迭代器?

另外,一个小的吹毛求疵:即使是我对 detail 命名空间的解决方法也是"错误的",因为它在我想要的(与标准迭代器相同)std::is_same_v<putc_iterator::reference, void>std::is_same_v<putc_iterator::reference, detail::proxy>

Boost 迭代器外观在当时很好,但现在它已经过时了,因为它不是很灵活(它不能很好地与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; }
};

最新更新