根据boost :: iterator_facade定义基于代理的OutputIterator

时间:2017-04-18 19:52:13

标签: c++ boost c++17 boost-iterators proxy-object

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

我试图通过将我的迭代器的成员typedef value_typereference设置为void来匹配所有标准OutputIterators的行为(因为这些类型是对于operator*没有返回引用的迭代器没有意义。

However, Boost complains:

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尚未定义。 I could pull proxy out into a detail namespace:

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

但这看起来很尴尬,绝对是不应该的。&#34;

这是iterator_facade中的错误吗?它是一个功能 - 不是一个错误?如果是后者,那么我假设如何使用它来创建OutputIterators?

另外,一个小小的挑剔:甚至我对细节命名空间的解决方法是&#34;错误&#34;从某种意义上来说,当我想要(与标准迭代器相同)时std::is_same_v<putc_iterator::reference, detail::proxy>std::is_same_v<putc_iterator::reference, void>

1 个答案:

答案 0 :(得分: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; }
};