0

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

我试图通过设置我的迭代器的成员 typedefsvalue_typereferenceto来匹配所有标准 OutputIterators 的行为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 可以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?

另外,一个小问题:即使我使用 detail 命名空间的解决方法也是“错误的”,因为std::is_same_v<putc_iterator::reference, detail::proxy>当我想要的(与标准迭代器相同)是std::is_same_v<putc_iterator::reference, void>.

4

1 回答 1

0

Boost Iterator Facade 当时很好,但现在它已经过时了,因为它不是很灵活(它不能很好地auto与 r 值引用一起使用,原则上可以通过取消引用 r 值迭代器来创建)。我不反对外观概念,但它可以升级到 C++11。

此外,现在使用 C++11 更容易从头开始编写迭代器。

无论如何,如果您需要定义 a referencejust 以符合要传递的参数,(并且如果您承诺不使用它)您可以使用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; }
};
于 2017-04-21T08:26:10.407 回答