4

我希望将 boost::optional 视为可以包含零个或一个元素的容器。从逻辑上讲,我应该能够为容器创建一个迭代器并在其上使用 boost::for_each。我的尝试如下,但无法编译。我在GodBolt上试过了。

https://godbolt.org/g/z5MFfe

下面的代码供参考。

#include <boost/optional.hpp>
#include <boost/range.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <iostream>

namespace boost {

    template <typename OT>
        class optional_iterator
        : public boost::iterator_facade<optional_iterator<OT>,
        typename OT::value_type,
        boost::forward_traversal_tag> {
            private:
                OT m_o;

            public:
                optional_iterator() : m_o(boost::none) {}
                explicit optional_iterator(OT& o) : m_o(o) {}

            private:
                friend class boost::iterator_core_access;

                void increment() { m_o = boost::none; }

                bool equal(OT& other) const { return this->m_o == other.m_o; }

                typename OT::value_type& dereference() { return *m_o; }
        };

    template <typename T>
        struct optional_iterators {
            typedef optional_iterator<boost::optional<T>> iterator;
            typedef optional_iterator<boost::optional<T> const> const_iterator;
        };

    template <class T>
        struct range_mutable_iterator<boost::optional<T>> {
            typedef typename optional_iterators<T>::iterator type;
        };

    template <class T>
        struct range_const_iterator<boost::optional<T> const> {
            typedef typename optional_iterators<T const>::const_iterator type;
        };

    template <class T>
        inline typename optional_iterators<T>::iterator range_begin(
                boost::optional<T>& x) {
            return typename optional_iterators<T>::iterator(x);
        }

    template <class T>
        inline typename optional_iterators<T>::const_iterator range_begin(
                boost::optional<T> const& x) {
            return typename optional_iterators<T>::const_iterator(x);
        }

    template <class T>
        inline typename optional_iterators<T>::iterator range_end(boost::optional<T>&x) {
            return typename optional_iterators<T>::iterator();
        }

    template <class T>
        inline typename optional_iterators<T>::const_iterator range_end(boost::optional<T> const & x) {
            return typename optional_iterators<T>::const_iterator();
        }
}  // namespace boost

int main() {
    auto a = boost::optional<int>(10);
    auto rb = range_begin(a);
    auto re = range_end(a);

   boost::for_each(a, [](int const& i) { std::cout << i; });
}

我相当确定我已经正确地实现了范围和迭代器的概念,但是我在 gcc 8.1 中得到了以下编译器错误(根据 godbolt)

#1 with x86-64 gcc 8.1
In file included from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/size_type.hpp:20,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/size.hpp:21,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/functions.hpp:20,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range.hpp:18,

                 from <source>:3:

/opt/compiler-explorer/libs/boost_1_64_0/boost/range/concepts.hpp: In instantiation of 'struct boost::SinglePassRangeConcept<boost::optional<int> >':

/opt/compiler-explorer/libs/boost_1_64_0/boost/concept/detail/has_constraints.hpp:32:62:   required by substitution of 'template<class Model> boost::concepts::detail::yes boost::concepts::detail::has_constraints_(Model*, boost::concepts::detail::wrap_constraints<Model, (& Model::constraints)>*) [with Model = boost::SinglePassRangeConcept<boost::optional<int> >]'

/opt/compiler-explorer/libs/boost_1_64_0/boost/concept/detail/has_constraints.hpp:42:5:   required from 'const bool boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::optional<int> > >::value'

/opt/compiler-explorer/libs/boost_1_64_0/boost/concept/detail/has_constraints.hpp:45:31:   required from 'struct boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::optional<int> > >'

/opt/compiler-explorer/libs/boost_1_64_0/boost/mpl/if.hpp:63:11:   required from 'struct boost::mpl::if_<boost::concepts::not_satisfied<boost::SinglePassRangeConcept<boost::optional<int> > >, boost::concepts::constraint<boost::SinglePassRangeConcept<boost::optional<int> > >, boost::concepts::requirement<boost::concepts::failed************ boost::SinglePassRangeConcept<boost::optional<int> >::************> >'

/opt/compiler-explorer/libs/boost_1_64_0/boost/concept/detail/general.hpp:51:8:   required from 'struct boost::concepts::requirement_<void (*)(boost::SinglePassRangeConcept<boost::optional<int> >)>'

/opt/compiler-explorer/libs/boost_1_64_0/boost/range/size.hpp:62:9:   required from 'UnaryFunction boost::range::for_each(SinglePassRange&, UnaryFunction) [with SinglePassRange = boost::optional<int>; UnaryFunction = main()::<lambda(const int&)>]'

<source>:75:59:   required from here

/opt/compiler-explorer/libs/boost_1_64_0/boost/range/concepts.hpp:272:17: error: no type named 'type' in 'struct boost::range_iterator<const boost::optional<int>, void>'

         >::type const_iterator;

                 ^~~~~~~~~~~~~~

In file included from /opt/compiler-explorer/libs/boost_1_64_0/boost/concept/assert.hpp:35,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/concept_check.hpp:20,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/concepts.hpp:19,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/size_type.hpp:20,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/size.hpp:21,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range/functions.hpp:20,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/range.hpp:18,

                 from <source>:3:

/opt/compiler-explorer/libs/boost_1_64_0/boost/range/concepts.hpp:279:9: error: no type named 'type' in 'struct boost::range_iterator<const boost::optional<int>, void>'

         BOOST_RANGE_CONCEPT_ASSERT((

         ^~~~~~~~~~~~~~~~~~~~~~~~~~

In file included from /opt/compiler-explorer/gcc-8.1.0/include/c++/8.1.0/algorithm:62,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/core/swap.hpp:25,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/optional/optional.hpp:27,

                 from /opt/compiler-explorer/libs/boost_1_64_0/boost/optional.hpp:15,

                 from <source>:2:

/opt/compiler-explorer/gcc-8.1.0/include/c++/8.1.0/bits/stl_algo.h:3876:5: error: '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = boost::optional_iterator<boost::optional<int> >; _Funct = main()::<lambda(const int&)>]', declared using local type 'main()::<lambda(const int&)>', is used but never defined [-fpermissive]

     for_each(_InputIterator __first, _InputIterator __last, _Function __f)

     ^~~~~~~~

/opt/compiler-explorer/gcc-8.1.0/include/c++/8.1.0/bits/stl_algo.h:3876:5: warning: '_Funct std::for_each(_IIter, _IIter, _Funct) [with _IIter = boost::optional_iterator<boost::optional<int> >; _Funct = main()::<lambda(const int&)>]' used but never defined

Compiler returned: 1
4

1 回答 1

1

我会保持简单:

template <typename T> auto make_range(optional<T>& opt) {
    T* addr = opt? std::addressof(*opt) : nullptr;
    return make_iterator_range(addr, opt? addr+1 : addr);
}

我没有对此进行测试,但它似乎很简单,也许可以正常工作。

于 2018-06-26T11:20:15.727 回答