Index: boost/ptr_container/ptr_list.hpp =================================================================== --- boost/ptr_container/ptr_list.hpp (revision 70851) +++ boost/ptr_container/ptr_list.hpp (working copy) @@ -107,5 +107,6 @@ } } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_list, 3) #endif Index: boost/ptr_container/ptr_map.hpp =================================================================== --- boost/ptr_container/ptr_map.hpp (revision 70851) +++ boost/ptr_container/ptr_map.hpp (working copy) @@ -164,4 +164,7 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_map, 5) +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_multimap, 5) + #endif Index: boost/ptr_container/ptr_array.hpp =================================================================== --- boost/ptr_container/ptr_array.hpp (revision 70851) +++ boost/ptr_container/ptr_array.hpp (working copy) @@ -231,4 +231,8 @@ } } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH_TUPLE(boost::ptr_array, 3, \ + (typename T, size_t size, typename CA), \ + (T,size,CA)) + #endif Index: boost/ptr_container/ptr_unordered_map.hpp =================================================================== --- boost/ptr_container/ptr_unordered_map.hpp (revision 70851) +++ boost/ptr_container/ptr_unordered_map.hpp (working copy) @@ -248,4 +248,7 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_unordered_map, 6) +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_unordered_multimap, 6) + #endif Index: boost/ptr_container/detail/reversible_ptr_container.hpp =================================================================== --- boost/ptr_container/detail/reversible_ptr_container.hpp (revision 70851) +++ boost/ptr_container/detail/reversible_ptr_container.hpp (working copy) @@ -39,6 +39,16 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) #pragma warning(push) #pragma warning(disable:4127) @@ -674,7 +684,23 @@ { return replace( idx, x.release() ); } - + + public: + // This needs to be a template to avoid ODR violation happens when + // instantiated in two different translation units; one which + // contains specialization of foreach::is_noncopyable, and + // another which doesn't. + // Being a template, this is instantiated only in translation units + // where BOOST_FOREACH is actually used. Such translation units + // are already mandated to contain the specialization of + // foreach::is_noncopyable not to cause ODR violation in the + // implementation of BOOST_FOREACH. + template + struct boost_foreach_is_noncopyable_impl + : mpl::and_< + mpl::not_ >, + foreach::is_noncopyable + > {}; }; // 'reversible_ptr_container' @@ -762,6 +788,26 @@ } // namespace 'boost' +// Enable use of BOOST_FOREACH over const reference of ptr_container +// of which value_type is noncopyable. +// See: http://www.boost.org/doc/html/foreach/extensibility.html#id862475 +#define BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH_SEQ(template_name, parameters_seq, arguments_seq) \ + namespace boost { namespace foreach { \ + template \ + struct is_noncopyable > \ + : template_name::template boost_foreach_is_noncopyable_impl<> {}; \ + }} +#define BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH_TUPLE(template_name, num_params, parameters_tuple, arguments_tuple) \ + BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH_SEQ(template_name, \ + BOOST_PP_TUPLE_TO_SEQ(num_params, parameters_tuple), \ + BOOST_PP_TUPLE_TO_SEQ(num_params, arguments_tuple)) +#define BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(template_name, num_params) \ + BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH_TUPLE(template_name, num_params, \ + (BOOST_PP_ENUM_PARAMS(num_params, class T)), \ + (BOOST_PP_ENUM_PARAMS(num_params, T))) +// Use this way for each public derived ptr_container ... +// BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(ptr_container_detail::reversible_ptr_container, 2) + #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) #pragma warning(pop) #endif Index: boost/ptr_container/ptr_set.hpp =================================================================== --- boost/ptr_container/ptr_set.hpp (revision 70851) +++ boost/ptr_container/ptr_set.hpp (working copy) @@ -155,4 +155,7 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_set, 4) +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_multiset, 4) + #endif Index: boost/ptr_container/ptr_circular_buffer.hpp =================================================================== --- boost/ptr_container/ptr_circular_buffer.hpp (revision 70851) +++ boost/ptr_container/ptr_circular_buffer.hpp (working copy) @@ -529,4 +529,6 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_circular_buffer, 3) + #endif Index: boost/ptr_container/ptr_vector.hpp =================================================================== --- boost/ptr_container/ptr_vector.hpp (revision 70851) +++ boost/ptr_container/ptr_vector.hpp (working copy) @@ -74,4 +74,6 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_vector, 3) + #endif Index: boost/ptr_container/ptr_unordered_set.hpp =================================================================== --- boost/ptr_container/ptr_unordered_set.hpp (revision 70851) +++ boost/ptr_container/ptr_unordered_set.hpp (working copy) @@ -239,4 +239,7 @@ } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_unordered_set, 5) +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_unordered_multiset, 5) + #endif Index: boost/ptr_container/ptr_deque.hpp =================================================================== --- boost/ptr_container/ptr_deque.hpp (revision 70851) +++ boost/ptr_container/ptr_deque.hpp (working copy) @@ -66,4 +66,6 @@ } } +BOOST_PTR_CONTAINER_CUSTOMIZE_FOREACH(boost::ptr_deque, 3) + #endif Index: libs/ptr_container/test/foreach_noncopyable_detection.cpp =================================================================== --- libs/ptr_container/test/foreach_noncopyable_detection.cpp (revision 0) +++ libs/ptr_container/test/foreach_noncopyable_detection.cpp (revision 0) @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct normal {}; +bool operator < (normal const&, normal const&); +bool operator == (normal const&, normal const&); +std::size_t hash_value(normal const&); + +struct abstract { virtual void f() const = 0; }; +bool operator < (abstract const&, abstract const&); +bool operator == (abstract const&, abstract const&); +std::size_t hash_value(abstract const&); + +struct noncopyable : boost::noncopyable {}; +bool operator < (noncopyable const&, noncopyable const&); +bool operator == (noncopyable const&, noncopyable const&); +std::size_t hash_value(noncopyable const&); + +using boost::foreach::is_noncopyable; + +template +struct test_noncopyable +{ + typedef boost::ptr_array ptr_array; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_deque ptr_deque; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_list ptr_list; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_map, CloneAllocator> ptr_map; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_multimap, CloneAllocator> ptr_multimap; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_set, CloneAllocator> ptr_set; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_multiset, CloneAllocator> ptr_multiset; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_vector ptr_vector; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_unordered_map, std::equal_to, CloneAllocator> ptr_unordered_map; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_unordered_multimap, std::equal_to, CloneAllocator> ptr_unordered_multimap; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_unordered_set, std::equal_to, CloneAllocator> ptr_unordered_set; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_unordered_multiset, std::equal_to, CloneAllocator> ptr_unordered_multiset; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); + + typedef boost::ptr_circular_buffer ptr_circular_buffer; + BOOST_STATIC_ASSERT(is_noncopyable::value == ExpectedNoncopyable); +}; + +test_noncopyable +normal_container_should_be_copyable; + +test_noncopyable +normal_view_should_be_copyable; + +test_noncopyable +abstract_container_should_be_noncopyable; + +test_noncopyable +abstract_view_should_be_copyable; + +test_noncopyable +noncopyable_container_should_be_noncopyable; + +test_noncopyable +noncopyable_view_should_be_copyable; Index: libs/ptr_container/test/Jamfile.v2 =================================================================== --- libs/ptr_container/test/Jamfile.v2 (revision 70851) +++ libs/ptr_container/test/Jamfile.v2 (working copy) @@ -40,5 +40,5 @@ [ sc-test ptr_circular_buffer ] [ sc-test const_element_containers ] # [ sc-test null_filter_iterator ] - + [ compile foreach_noncopyable_detection.cpp ] ;