diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 77d55b1d..c5d143ea 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -193,6 +193,18 @@ #endif #endif +// BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + +#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) +#if BOOST_COMP_CLANG && __cplusplus >= 201703 +#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 1 +#endif +#endif + +#if !defined(BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES) +#define BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES 0 +#endif + namespace boost { namespace unordered { namespace iterator_detail { diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index bae3aa2f..e32f6123 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -831,6 +831,81 @@ namespace boost { #endif }; // class template unordered_map +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + namespace detail { + template + using iter_key_t = + typename std::iterator_traits::value_type::first_type; + template + using iter_val_t = + typename std::iterator_traits::value_type::second_type; + template + using iter_to_alloc_t = + typename std::pair const, iter_val_t >; + } + + template >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::iter_to_alloc_t > > + unordered_map(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_map, + boost::unordered::detail::iter_val_t, Hash, Pred, + Allocator>; + + template , + class Pred = std::equal_to, + class Allocator = std::allocator > > + unordered_map(std::initializer_list >, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_map; + + template + unordered_map(InputIterator, InputIterator, std::size_t, Allocator) + ->unordered_map, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template + unordered_map(InputIterator, InputIterator, Allocator) + ->unordered_map, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template + unordered_map(InputIterator, InputIterator, std::size_t, Hash, Allocator) + ->unordered_map, + boost::unordered::detail::iter_val_t, Hash, + std::equal_to >, + Allocator>; + + template + unordered_map( + std::initializer_list >, std::size_t, Allocator) + ->unordered_map, std::equal_to, Allocator>; + + template + unordered_map(std::initializer_list >, Allocator) + ->unordered_map, std::equal_to, Allocator>; + + template + unordered_map(std::initializer_list >, std::size_t, + Hash, Allocator) + ->unordered_map, Allocator>; + +#endif + template class unordered_multimap { @@ -1363,6 +1438,73 @@ namespace boost { #endif }; // class template unordered_multimap +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + template >, + class Pred = + std::equal_to >, + class Allocator = std::allocator< + boost::unordered::detail::iter_to_alloc_t > > + unordered_multimap(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_multimap, + boost::unordered::detail::iter_val_t, Hash, Pred, + Allocator>; + + template , + class Pred = std::equal_to, + class Allocator = std::allocator > > + unordered_multimap(std::initializer_list >, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_multimap; + + template + unordered_multimap(InputIterator, InputIterator, std::size_t, Allocator) + ->unordered_multimap, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template + unordered_multimap(InputIterator, InputIterator, Allocator) + ->unordered_multimap, + boost::unordered::detail::iter_val_t, + boost::hash >, + std::equal_to >, + Allocator>; + + template + unordered_multimap( + InputIterator, InputIterator, std::size_t, Hash, Allocator) + ->unordered_multimap, + boost::unordered::detail::iter_val_t, Hash, + std::equal_to >, + Allocator>; + + template + unordered_multimap( + std::initializer_list >, std::size_t, Allocator) + ->unordered_multimap, std::equal_to, + Allocator>; + + template + unordered_multimap( + std::initializer_list >, Allocator) + ->unordered_multimap, std::equal_to, + Allocator>; + + template + unordered_multimap(std::initializer_list >, + std::size_t, Hash, Allocator) + ->unordered_multimap, Allocator>; + +#endif + //////////////////////////////////////////////////////////////////////////// template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index e01c5586..bbd243d0 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -545,6 +545,52 @@ namespace boost { #endif }; // class template unordered_set +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + template ::value_type>, + class Pred = + std::equal_to::value_type>, + class Allocator = std::allocator< + typename std::iterator_traits::value_type> > + unordered_set(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_set::value_type, + Hash, Pred, Allocator>; + + template , + class Pred = std::equal_to, class Allocator = std::allocator > + unordered_set(std::initializer_list, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_set; + + template + unordered_set(InputIterator, InputIterator, std::size_t, Allocator) + ->unordered_set::value_type, + boost::hash::value_type>, + std::equal_to::value_type>, + Allocator>; + + template + unordered_set(InputIterator, InputIterator, std::size_t, Hash, Allocator) + ->unordered_set::value_type, + Hash, + std::equal_to::value_type>, + Allocator>; + + template + unordered_set(std::initializer_list, std::size_t, Allocator) + ->unordered_set, std::equal_to, Allocator>; + + template + unordered_set(std::initializer_list, std::size_t, Hash, Allocator) + ->unordered_set, Allocator>; + +#endif + template class unordered_multiset { #if defined(BOOST_UNORDERED_USE_MOVE) @@ -1049,6 +1095,55 @@ namespace boost { #endif }; // class template unordered_multiset +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + + template ::value_type>, + class Pred = + std::equal_to::value_type>, + class Allocator = std::allocator< + typename std::iterator_traits::value_type> > + unordered_multiset(InputIterator, InputIterator, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_multiset< + typename std::iterator_traits::value_type, Hash, Pred, + Allocator>; + + template , + class Pred = std::equal_to, class Allocator = std::allocator > + unordered_multiset(std::initializer_list, + std::size_t = boost::unordered::detail::default_bucket_count, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + ->unordered_multiset; + + template + unordered_multiset(InputIterator, InputIterator, std::size_t, Allocator) + ->unordered_multiset< + typename std::iterator_traits::value_type, + boost::hash::value_type>, + std::equal_to::value_type>, + Allocator>; + + template + unordered_multiset( + InputIterator, InputIterator, std::size_t, Hash, Allocator) + ->unordered_multiset< + typename std::iterator_traits::value_type, Hash, + std::equal_to::value_type>, + Allocator>; + + template + unordered_multiset(std::initializer_list, std::size_t, Allocator) + ->unordered_multiset, std::equal_to, Allocator>; + + template + unordered_multiset(std::initializer_list, std::size_t, Hash, Allocator) + ->unordered_multiset, Allocator>; + +#endif + //////////////////////////////////////////////////////////////////////////// template unordered_set::unordered_set() diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e06b569f..67c31d98 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -63,6 +63,7 @@ test-suite unordered [ run unordered/equality_tests.cpp ] [ run unordered/swap_tests.cpp ] [ run unordered/detail_tests.cpp ] + [ run unordered/deduction_tests.cpp ] [ run unordered/compile_set.cpp : : : BOOST_UNORDERED_USE_MOVE diff --git a/test/unordered/deduction_tests.cpp b/test/unordered/deduction_tests.cpp new file mode 100644 index 00000000..f1e14c94 --- /dev/null +++ b/test/unordered/deduction_tests.cpp @@ -0,0 +1,347 @@ +#include +#include +#include + +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES +struct hash_equals +{ + template bool operator()(T const& x) const + { + boost::hash hf; + return hf(x); + } + + template bool operator()(T const& x, T const& y) const + { + std::equal_to eq; + return eq(x, y); + } +}; + +template struct test_allocator +{ + typedef T value_type; + test_allocator() = default; + template test_allocator(test_allocator const&) {} + T* allocate(std::size_t n) const { return (T*)malloc(sizeof(T) * n); } + void deallocate(T* ptr, std::size_t) const { free(ptr); } + bool operator==(test_allocator const&) { return true; } + bool operator!=(test_allocator const&) { return false; } +}; +#endif + +int main() +{ + std::cout << "BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES: " + << BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES << std::endl; + +#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES + std::vector > x; + x.push_back(std::make_pair(1, 3)); + x.push_back(std::make_pair(5, 10)); + test_allocator > pair_allocator; + hash_equals f; + + // unordered_map + + /* + template>, + class Pred = equal_to>, + class Allocator = allocator>> + unordered_map(InputIterator, InputIterator, typename see below::size_type = + see below, + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map, iter_val_t, + Hash, Pred, + Allocator>; + */ + + { + boost::unordered_map m(x.begin(), x.end()); + static_assert( + std::is_same >::value); + } + + /* Ambiguous: + { + boost::unordered_map m(x.begin(), x.end(), 0, std::hash()); + static_assert(std::is_same>>::value); + } + + { + boost::unordered_map m(x.begin(), x.end(), 0, std::hash(), + std::equal_to()); + static_assert(std::is_same, std::equal_to>>::value); + } + */ + + { + boost::unordered_map m(x.begin(), x.end(), 0, std::hash(), + std::equal_to(), pair_allocator); + static_assert(std::is_same, std::equal_to, + test_allocator > > >::value); + } + + /* + template, + class Pred = equal_to, class Allocator = allocator>> + unordered_map(initializer_list>, + typename see below::size_type = see below, Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> unordered_map; + */ + + { + boost::unordered_map m({std::pair(1, 2)}); + static_assert( + std::is_same >::value); + } + + /* Ambiguous + { + boost::unordered_map m({std::pair(1,2)}, 0, + std::hash()); + static_assert(std::is_same>>::value); + } + + { + boost::unordered_map m({std::pair(1,2)}, 0, + std::hash(), std::equal_to()); + static_assert(std::is_same, std::equal_to>>::value); + } + */ + + { + boost::unordered_map m( + {std::pair(1, 2)}, 0, f, f, pair_allocator); + static_assert(std::is_same > > >::value); + } + + /* + template + unordered_map(InputIterator, InputIterator, typename see below::size_type, + Allocator) + -> unordered_map, iter_val_t, + hash>, + equal_to>, + Allocator>; + */ + + /* Ambiguous + { + boost::unordered_map m(x.begin(), x.end(), 0u, pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + /* + template + unordered_map(InputIterator, InputIterator, Allocator) + -> unordered_map, iter_val_t, + hash>, + equal_to>, + Allocator>; + */ + + /* No constructor: + { + boost::unordered_map m(x.begin(), x.end(), pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + /* + template + unordered_map(InputIterator, InputIterator, typename see below::size_type, + Hash, Allocator) + -> unordered_map, iter_val_t, + Hash, + equal_to>, Allocator>; + */ + + /* Ambiguous + { + boost::unordered_map m(x.begin(), x.end(), 0u, f, pair_allocator); + static_assert(std::is_same, test_allocator>>>::value); + } + */ + + /* + template + unordered_map(initializer_list>, typename see + below::size_type, + Allocator) + -> unordered_map, equal_to, Allocator>; + */ + + /* Ambiguous + { + boost::unordered_map m({std::pair(1,2)}, 0, pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + /* + template + unordered_map(initializer_list>, Allocator) + -> unordered_map, equal_to, Allocator>; + */ + + { + boost::unordered_map m({std::pair(1, 2)}, pair_allocator); + static_assert(std::is_same, std::equal_to, + test_allocator > > >::value); + } + + /* + template + unordered_map(initializer_list>, typename see + below::size_type, Hash, + Allocator) + -> unordered_map, Allocator>; + */ + + /* Ambiguous + { + boost::unordered_map m({std::pair(1,2)}, 0, f, + pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + // unordered_multimap + + { + boost::unordered_multimap m(x.begin(), x.end()); + static_assert( + std::is_same >::value); + } + + /* Ambiguous: + { + boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash()); + static_assert(std::is_same>>::value); + } + + { + boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash(), + std::equal_to()); + static_assert(std::is_same, std::equal_to>>::value); + } + */ + + { + boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash(), + std::equal_to(), pair_allocator); + static_assert(std::is_same, std::equal_to, + test_allocator > > >::value); + } + + { + boost::unordered_multimap m({std::pair(1, 2)}); + static_assert( + std::is_same >::value); + } + + /* Ambiguous + { + boost::unordered_multimap m({std::pair(1,2)}, 0, + std::hash()); + static_assert(std::is_same>>::value); + } + + { + boost::unordered_multimap m({std::pair(1,2)}, 0, + std::hash(), std::equal_to()); + static_assert(std::is_same, std::equal_to>>::value); + } + */ + + { + boost::unordered_multimap m( + {std::pair(1, 2)}, 0, f, f, pair_allocator); + static_assert(std::is_same > > >::value); + } + + /* Ambiguous + { + boost::unordered_multimap m(x.begin(), x.end(), 0u, pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + /* No constructor: + { + boost::unordered_multimap m(x.begin(), x.end(), pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + /* Ambiguous + { + boost::unordered_multimap m(x.begin(), x.end(), 0u, f, pair_allocator); + static_assert(std::is_same, test_allocator>>>::value); + } + + { + boost::unordered_multimap m({std::pair(1,2)}, 0, + pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); + } + */ + + { + boost::unordered_multimap m( + {std::pair(1, 2)}, pair_allocator); + static_assert(std::is_same, std::equal_to, + test_allocator > > >::value); + } + +/* Ambiguous +{ + boost::unordered_multimap m({std::pair(1,2)}, 0, f, +pair_allocator); + static_assert(std::is_same, std::equal_to, test_allocator>>>::value); +} +*/ + +#endif +}