From ce12d2aec53a17f982febcd7c3e83deb97b1b593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 22 Mar 2026 17:26:15 +0100 Subject: [PATCH] Fixes #334 ("Wrong overload resolution protection in implementation of P2363R5") and adds tests with transparent comparator for associative containers. --- include/boost/container/flat_set.hpp | 14 +++++----- include/boost/container/set.hpp | 10 ++++--- test/flat_map_test.cpp | 28 ++++++++++---------- test/flat_set_test.cpp | 15 ++++++++--- test/map_test.cpp | 15 ++++++++--- test/set_test.cpp | 39 +++++++++++++++++++++++++--- 6 files changed, 88 insertions(+), 33 deletions(-) diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 15d1018..15d86b7 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -411,7 +411,7 @@ class flat_set flat_set& operator=(std::initializer_list il) { this->clear(); - this->insert(il.begin(), il.end()); + this->tree_t::insert_unique_range(il.begin(), il.end()); return *this; } #endif @@ -737,10 +737,12 @@ class flat_set template inline BOOST_CONTAINER_DOC1ST ( iterator - , typename dtl::enable_if_transparent< key_compare - BOOST_MOVE_I K - BOOST_MOVE_I iterator - >::type) //transparent + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I iterator + >::type) insert(const_iterator p, K &&x) { return this->tree_t::insert_unique(p, boost::forward(x)); } @@ -1549,7 +1551,7 @@ class flat_multiset flat_multiset& operator=(std::initializer_list il) { this->clear(); - this->insert(il.begin(), il.end()); + this->tree_t::insert_equal_range(il.begin(), il.end()); return *this; } #endif diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index 6aee281..d912c13 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -656,10 +656,12 @@ class set template inline BOOST_CONTAINER_DOC1ST ( iterator - , typename dtl::enable_if_transparent< key_compare - BOOST_MOVE_I K - BOOST_MOVE_I iterator - >::type) //transparent + , typename dtl::enable_if_c< + dtl::is_transparent::value && //transparent + !dtl::is_convertible::value && //not convertible to iterator + !dtl::is_convertible::value //not convertible to const_iterator + BOOST_MOVE_I iterator + >::type) insert(const_iterator p, K &&x) { return this->base_t::insert_unique_hint_convertible(p, boost::forward(x)); } diff --git a/test/flat_map_test.cpp b/test/flat_map_test.cpp index ec6d104..fa63626 100644 --- a/test/flat_map_test.cpp +++ b/test/flat_map_test.cpp @@ -193,7 +193,7 @@ bool constructor_template_auto_deduction_test() }}} -template +template struct GetMapContainer { template @@ -202,21 +202,21 @@ struct GetMapContainer typedef std::pair type_t; typedef flat_map< ValueType , ValueType - , std::less + , typename dtl::if_c >::type , typename boost::container::dtl::container_or_allocator_rebind::type > map_type; typedef flat_multimap< ValueType , ValueType - , std::less + , typename dtl::if_c >::type , typename boost::container::dtl::container_or_allocator_rebind::type > multimap_type; }; }; //To test default parameters -template<> -struct GetMapContainer +template +struct GetMapContainer { template struct apply @@ -389,15 +389,6 @@ int main() return 1; } - if (0 != test::flat_map_test - < GetMapContainer::apply::map_type - , MyStdMap - , GetMapContainer::apply::multimap_type - , MyStdMultiMap>()) { - std::cout << "Error in flat_map_test >" << std::endl; - return 1; - } - if (0 != test::flat_map_test < GetMapContainer >::apply::map_type , MyStdMap @@ -433,6 +424,15 @@ int main() std::cout << "Error in flat_map_test >" << std::endl; return 1; } + + if (0 != test::flat_map_test + < GetMapContainer, true>::apply::map_type + , MyStdMap + , GetMapContainer, true>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in flat_map_test, transparent >" << std::endl; + return 1; + } } if(!boost::container::test::test_map_support_for_initialization_list_for >()) diff --git a/test/flat_set_test.cpp b/test/flat_set_test.cpp index ff62d20..1011243 100644 --- a/test/flat_set_test.cpp +++ b/test/flat_set_test.cpp @@ -532,19 +532,19 @@ bool test_heterogeneous_lookup_by_partial_key() }}} -template +template struct GetSetContainer { template struct apply { typedef flat_set < ValueType - , std::less + , typename dtl::if_c >::type , typename boost::container::dtl::container_or_allocator_rebind::type > set_type; typedef flat_multiset < ValueType - , std::less + , typename dtl::if_c >::type , typename boost::container::dtl::container_or_allocator_rebind::type > multiset_type; }; @@ -733,6 +733,15 @@ int main() std::cout << "Error in set_test >" << std::endl; return 1; } + + if (0 != test::set_test + < GetSetContainer, true>::apply::set_type + , MyStdSet + , GetSetContainer, true>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test >>, transparent" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/map_test.cpp b/test/map_test.cpp index cb0ba23..dd27164 100644 --- a/test/map_test.cpp +++ b/test/map_test.cpp @@ -220,7 +220,7 @@ bool node_type_test() return true; } -template +template struct GetAllocatorMap { template @@ -228,7 +228,7 @@ struct GetAllocatorMap { typedef map< ValueType , ValueType - , std::less + , typename dtl::if_c >::type , typename allocator_traits ::template portable_rebind_alloc< std::pair >::type , typename boost::container::tree_assoc_options @@ -238,7 +238,7 @@ struct GetAllocatorMap typedef multimap< ValueType , ValueType - , std::less + , typename dtl::if_c >::type , typename allocator_traits ::template portable_rebind_alloc< std::pair >::type , typename boost::container::tree_assoc_options @@ -489,6 +489,15 @@ int main () std::cout << "Error in map_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::map_test + < GetAllocatorMap, red_black_tree, true>::apply::map_type + , MyStdMap + , GetAllocatorMap, red_black_tree, true>::apply::multimap_type + , MyStdMultiMap>()) { + std::cout << "Error in map_test, red_black_tree>>, transparent" << std::endl; + return 1; + } } //////////////////////////////////// diff --git a/test/set_test.cpp b/test/set_test.cpp index a91abfa..1087a60 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -1,3 +1,4 @@ + ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost @@ -346,14 +347,14 @@ bool constructor_template_auto_deduction_test() }}} //boost::container::test -template +template struct GetAllocatorSet { template struct apply { typedef set < ValueType - , std::less + , typename dtl::if_c >::type , typename allocator_traits ::template portable_rebind_alloc::type , typename boost::container::tree_assoc_options @@ -362,7 +363,7 @@ struct GetAllocatorSet > set_type; typedef multiset < ValueType - , std::less + , typename dtl::if_c >::type , typename allocator_traits ::template portable_rebind_alloc::type , typename boost::container::tree_assoc_options @@ -504,6 +505,24 @@ int main () std::cout << "Error in set_test, red_black_tree>" << std::endl; return 1; } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>" << std::endl; + return 1; + } + + if (0 != test::set_test + < GetAllocatorSet, red_black_tree, true>::apply::set_type + , MyStdSet + , GetAllocatorSet, red_black_tree, true>::apply::multiset_type + , MyStdMultiSet>()) { + std::cout << "Error in set_test, red_black_tree>>, transparent" << std::endl; + return 1; + } } //////////////////////////////////// @@ -621,3 +640,17 @@ int main () return 0; } + +/* +#include +#include + +int main() +{ + using set = boost::container::set>; + + set s; + const set cs; + s.insert(cs.begin(), cs.end()); +} +*/ \ No newline at end of file