我写了这个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; }
};