From 3d3560c12d8299d0ed11a90dc505e3002c4d9e3c Mon Sep 17 00:00:00 2001 From: Kohei Takahashi Date: Thu, 18 Sep 2014 16:37:28 +0900 Subject: [PATCH] Avoid 'reference to reference' error in C++03. Some (strict) C++03 compilers (e.g. `gcc -std=c++03`) reject 'reference-to-reference' in the template and typedef which described in CWG DR106 [1]. In such situations, iterator_facade rejects reference type as a value type and some special iterators will become ill-formed: the test libs/range/test/join.hpp might be descriptive. [1] http://www.open-std.org/Jtc1/sc22/wg21/docs/cwg_defects.html#106 Signed-off-by: Kohei Takahashi --- include/boost/iterator/is_lvalue_iterator.hpp | 3 +- .../boost/iterator/is_readable_iterator.hpp | 3 +- include/boost/iterator/iterator_facade.hpp | 11 +++- test/iterator_facade.cpp | 65 ++++++++++++++++++- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/include/boost/iterator/is_lvalue_iterator.hpp b/include/boost/iterator/is_lvalue_iterator.hpp index 20c4f38..5607a0f 100644 --- a/include/boost/iterator/is_lvalue_iterator.hpp +++ b/include/boost/iterator/is_lvalue_iterator.hpp @@ -9,6 +9,7 @@ #include #include +#include #include // should be the last #includes @@ -52,7 +53,7 @@ namespace detail // convertible to Value const& struct conversion_eater { - conversion_eater(Value&); + conversion_eater(typename add_lvalue_reference::type); }; static char tester(conversion_eater, int); diff --git a/include/boost/iterator/is_readable_iterator.hpp b/include/boost/iterator/is_readable_iterator.hpp index 3f08b92..d2e5e9f 100644 --- a/include/boost/iterator/is_readable_iterator.hpp +++ b/include/boost/iterator/is_readable_iterator.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -26,7 +27,7 @@ namespace detail template struct is_readable_iterator_impl { - static char tester(Value&, int); + static char tester(typename add_lvalue_reference::type, int); static char (& tester(any_conversion_eater, ...) )[2]; template diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index c08a869..7b11d0a 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -284,7 +285,15 @@ namespace iterators { : mpl::eval_if< mpl::and_< // A proxy is only needed for readable iterators - is_convertible + is_convertible< + Reference + // Use add_lvalue_reference to form `reference to Value` due to + // some (strict) C++03 compilers (e.g. `gcc -std=c++03`) reject + // 'reference-to-reference' in the template which described in CWG + // DR106. + // http://www.open-std.org/Jtc1/sc22/wg21/docs/cwg_defects.html#106 + , typename add_lvalue_reference::type + > // No multipass iterator can have values that disappear // before positions can be re-visited diff --git a/test/iterator_facade.cpp b/test/iterator_facade.cpp index 9585298..9200cc1 100644 --- a/test/iterator_facade.cpp +++ b/test/iterator_facade.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -49,14 +50,14 @@ class counter_iterator struct proxy { proxy(int& x) : state(x) {} - + operator int const&() const { return state; } int& operator=(int x) { state = x; return state; } - + int& state; }; @@ -128,6 +129,61 @@ template void same_type(U const&) { BOOST_MPL_ASSERT((boost::is_same)); } +template +struct abstract_iterator + : boost::iterator_facade< + abstract_iterator + , A & + // In order to be value type as a reference, traversal category has + // to satisfy least forward traversal. + , boost::forward_traversal_tag + , A & + > +{ + abstract_iterator(I iter) : iter(iter) {} + + void increment() + { ++iter; } + + A & dereference() const + { return *iter; } + + bool equal(abstract_iterator const& y) const + { return iter == y.iter; } + + I iter; +}; + +struct base +{ + virtual void assign(const base &) = 0; + virtual bool equal(const base &) const = 0; +}; + +struct derived : base +{ + derived(int state) : state(state) { } + derived(const derived &d) : state(d.state) { } + derived(const base &b) { derived::assign(b); } + + virtual void assign(const base &b) + { + state = boost::polymorphic_cast(&b)->state; + } + + virtual bool equal(const base &b) const + { + return state == boost::polymorphic_cast(&b)->state; + } + + int state; +}; + +inline bool operator==(const base &lhs, const base &rhs) +{ + return lhs.equal(rhs); +} + int main() { { @@ -162,5 +218,10 @@ int main() BOOST_TEST(i.m_x == 2); } + { + derived d(1); + boost::readable_iterator_test(abstract_iterator(&d), derived(1)); + } + return boost::report_errors(); }