diff --git a/include/boost/iterator/iterator_facade.hpp b/include/boost/iterator/iterator_facade.hpp index 20cde3d..c4b5ae4 100644 --- a/include/boost/iterator/iterator_facade.hpp +++ b/include/boost/iterator/iterator_facade.hpp @@ -150,54 +150,25 @@ namespace iterators { // value must be read and stored away before the increment occurs // so that *a++ yields the originally referenced element and not // the next one. - template - class postfix_increment_dereference_proxy + template + class postfix_increment_proxy { - typedef Value value_type; - public: -#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - template - explicit postfix_increment_dereference_proxy(OtherValue&& x) - : stored_value(static_cast< OtherValue&& >(x)) - {} -#else - explicit postfix_increment_dereference_proxy(value_type const& x) - : stored_value(x) - {} + typedef typename iterator_value::type value_type; - explicit postfix_increment_dereference_proxy(value_type& x) - : stored_value(x) + public: + explicit postfix_increment_proxy(Iterator const& x) + : stored_iterator(x) + , stored_value(*x) {} -#endif // Returning a mutable reference allows nonsense like // (*r++).mutate(), but it imposes fewer assumptions about the // behavior of the value_type. In particular, recall that // (*r).mutate() is legal if operator* returns by value. // Provides readability of *r++ - operator value_type&() const + value_type& operator*() const { - return this->stored_value; - } - - private: - mutable value_type stored_value; - }; - - template - class postfix_increment_proxy - { - typedef typename iterator_value::type value_type; - public: - explicit postfix_increment_proxy(Iterator const& x) - : stored_iterator(x) - , dereference_proxy(*x) - {} - - postfix_increment_dereference_proxy const& - operator*() const - { - return dereference_proxy; + return stored_value; } // Provides X(r++) @@ -206,9 +177,15 @@ namespace iterators { return stored_iterator; } + // Provides (r++)->foo() + value_type* operator->() const + { + return boost::addressof(stored_value); + } + private: Iterator stored_iterator; - postfix_increment_dereference_proxy dereference_proxy; + mutable value_type stored_value; }; @@ -304,6 +281,8 @@ namespace iterators { template class writable_postfix_increment_proxy { + typedef typename iterator_value::type value_type; + public: explicit writable_postfix_increment_proxy(Iterator const& x) : dereference_proxy(x) @@ -321,6 +300,12 @@ namespace iterators { return dereference_proxy.stored_iterator; } + // Provides (r++)->foo() + value_type* operator->() const + { + return boost::addressof(dereference_proxy.stored_value); + } + private: writable_postfix_increment_dereference_proxy dereference_proxy; }; diff --git a/test/iterator_facade.cpp b/test/iterator_facade.cpp index d9e5eb6..33e678a 100644 --- a/test/iterator_facade.cpp +++ b/test/iterator_facade.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include // This is a really, really limited test so far. All we're doing // right now is checking that the postfix++ proxy for single-pass @@ -63,7 +63,23 @@ struct proxy struct value { - void mutator() {} // non-const member function + int increment_count; + int private_mutator_count; + int& shared_mutator_count; + + explicit value(int& shared_mutator_count) : + increment_count(0), + private_mutator_count(0), + shared_mutator_count(shared_mutator_count) + { + } + + // non-const member function + void mutator() + { + ++private_mutator_count; + ++shared_mutator_count; + } }; struct input_iter @@ -75,21 +91,25 @@ struct input_iter > { public: - input_iter() {} + explicit input_iter(value& val) : state(&val) {} void increment() { + ++(state->increment_count); } value dereference() const { - return value(); + return *state; } bool equal(input_iter const&) const { return false; } + + private: + value* state; }; template @@ -198,13 +218,30 @@ int main() { // test for a fix to http://tinyurl.com/zuohe // These two lines should be equivalent (and both compile) - input_iter p; + int shared_mutator_count = 0; + value val(shared_mutator_count); + input_iter p(val); (*p).mutator(); p->mutator(); + BOOST_TEST_EQ(val.increment_count, 0); + BOOST_TEST_EQ(val.private_mutator_count, 0); // mutator() should be invoked on an object returned by value + BOOST_TEST_EQ(shared_mutator_count, 2); same_type(p.operator->()); } + { + // Test that accessing dereferenced value of a post-incremented iterator works + int shared_mutator_count = 0; + value val(shared_mutator_count); + input_iter p(val); + (*p++).mutator(); + (p++)->mutator(); + BOOST_TEST_EQ(val.increment_count, 2); + BOOST_TEST_EQ(val.private_mutator_count, 0); // mutator() should be invoked on an object returned by value + BOOST_TEST_EQ(shared_mutator_count, 2); + } + { int x = 0; iterator_with_proxy_reference i(x);