diff --git a/include/boost/intrusive/detail/iterator.hpp b/include/boost/intrusive/detail/iterator.hpp index c25be43..41ffca1 100644 --- a/include/boost/intrusive/detail/iterator.hpp +++ b/include/boost/intrusive/detail/iterator.hpp @@ -147,7 +147,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_tag @@ -155,7 +155,7 @@ typename iterator_enable_if_tag::type iterator_advance(InputIt& it, Distance n) { while(n--) - ++it; + ++it; } template @@ -163,9 +163,9 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_tag @@ -181,7 +181,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag iterator_advance(InputIt& it, Distance n) { while(n--) - ++it; + ++it; } template @@ -190,7 +190,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag iterator_advance(InputIt& it, Distance n) { while(n--) - ++it; + ++it; } template @@ -199,7 +199,7 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag iterator_advance(InputIt& it, Distance n) { while(n--) - ++it; + ++it; } template @@ -208,9 +208,9 @@ BOOST_INTRUSIVE_FORCEINLINE typename iterator_enable_if_convertible_tag iterator_advance(InputIt& it, Distance n) { for (; 0 < n; --n) - ++it; + ++it; for (; n < 0; ++n) - --it; + --it; } class fake{}; @@ -233,7 +233,7 @@ typename iterator_disable_if_tag_difference_type { typename iterator_traits::difference_type off = 0; while(first != last){ - ++off; + ++off; ++first; } return off; diff --git a/include/boost/intrusive/detail/tree_value_compare.hpp b/include/boost/intrusive/detail/tree_value_compare.hpp index c78da0a..6b05f22 100644 --- a/include/boost/intrusive/detail/tree_value_compare.hpp +++ b/include/boost/intrusive/detail/tree_value_compare.hpp @@ -27,7 +27,7 @@ namespace boost{ namespace intrusive{ //Needed to support smart references to value types -template +template struct disable_if_smartref_to : detail::disable_if_c < detail::is_same @@ -39,7 +39,8 @@ struct disable_if_smartref_to < typename pointer_rebind < ValuePtr , const typename boost::movelib::pointer_element::type>::type> - ::reference>::value + ::reference>::value, + R > {}; @@ -51,6 +52,10 @@ template< class ValuePtr, class KeyCompare, class KeyOfValue, class Ret = bool struct tree_value_compare : public boost::intrusive::detail::ebo_functor_holder { +private: + struct sfinae_type; + +public: typedef typename boost::movelib::pointer_element::type value_type; typedef KeyCompare key_compare; @@ -88,7 +93,7 @@ struct tree_value_compare template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(nonkey); } BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const key_type &key1, const key_type &key2) const @@ -105,22 +110,22 @@ struct tree_value_compare template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const key_type &key1, const U &nonkey2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(key1, nonkey2); } template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey1, const key_type &key2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(nonkey1, key2); } template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const value_type &value1, const U &nonvalue2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(KeyOfValue()(value1), nonvalue2); } template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonvalue1, const value_type &value2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(nonvalue1, KeyOfValue()(value2)); } }; @@ -128,6 +133,10 @@ template struct tree_value_compare : public boost::intrusive::detail::ebo_functor_holder { +private: + struct sfinae_type; + +public: typedef typename boost::movelib::pointer_element::type value_type; typedef KeyCompare key_compare; @@ -163,7 +172,7 @@ struct tree_value_compare template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const U &nonkey - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(nonkey); } BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const key_type &key1, const key_type &key2) const @@ -171,12 +180,12 @@ struct tree_value_compare template BOOST_INTRUSIVE_FORCEINLINE Ret operator()( const key_type &key1, const U &nonkey2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(key1, nonkey2); } template BOOST_INTRUSIVE_FORCEINLINE Ret operator()(const U &nonkey1, const key_type &key2 - , typename disable_if_smartref_to::type* = 0) const + , typename disable_if_smartref_to::type = 0) const { return this->key_comp()(nonkey1, key2); } }; diff --git a/test/voidptr_key_test.cpp b/test/voidptr_key_test.cpp new file mode 100644 index 0000000..c605599 --- /dev/null +++ b/test/voidptr_key_test.cpp @@ -0,0 +1,94 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Andrey Semashev 2018. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include // std::less + +// The test verifies that the set implementation does not use void* as auxiliary arguments for SFINAE +// in internal functions, which would make overload resolution ambiguous if user's key type is also void*. + +typedef boost::intrusive::set_base_hook< + boost::intrusive::link_mode< boost::intrusive::safe_link >, + boost::intrusive::tag< struct for_set_element_lookup_by_key >, + boost::intrusive::optimize_size< true > +> set_element_hook_t; + +struct set_element : + public set_element_hook_t +{ + struct order_by_key + { + typedef bool result_type; + + result_type operator() (set_element const& left, set_element const& right) const + { + return std::less< void* >()(left.m_key, right.m_key); + } + result_type operator() (void* left, set_element const& right) const + { + return std::less< void* >()(left, right.m_key); + } + result_type operator() (set_element const& left, void* right) const + { + return std::less< void* >()(left.m_key, right); + } + }; + + void* m_key; + + explicit set_element(void* key) : m_key(key) {} + + BOOST_DELETED_FUNCTION(set_element(set_element const&)) + BOOST_DELETED_FUNCTION(set_element& operator=(set_element const&)) +}; + +typedef boost::intrusive::set< + set_element, + boost::intrusive::base_hook< set_element_hook_t >, + boost::intrusive::compare< set_element::order_by_key >, + boost::intrusive::constant_time_size< true > +> set_t; + +void test_set() +{ + int v1 = 0, v2 = 1, v3 = 2; + set_element e1(&v1), e2(&v2), e3(&v3); + + set_t s; + s.insert(e1); + s.insert(e2); + + set_t::iterator it = s.find(e1); + BOOST_TEST(it != s.end() && &*it == &e1); + + it = s.find((void*)&v2, set_element::order_by_key()); + BOOST_TEST(it != s.end() && &*it == &e2); + + it = s.find(e3); + BOOST_TEST(it == s.end()); + + it = s.find((void*)&v3, set_element::order_by_key()); + BOOST_TEST(it == s.end()); + + s.clear(); +} + +int main() +{ + test_set(); + + return boost::report_errors(); +}