Skip to content

Commit 7df5d50

Browse files
author
Dawn Perchik
committed
P0919R3 Heterogeneous lookup for unordered containers
1 parent 6a4eb32 commit 7df5d50

File tree

2 files changed

+144
-31
lines changed

2 files changed

+144
-31
lines changed

source/containers.tex

Lines changed: 142 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,9 +2171,10 @@
21712171

21722172
\pnum
21732173
\indextext{unordered associative containers!equality function}%
2174-
Two values \tcode{k1} and \tcode{k2} of type \tcode{Key} are
2174+
Two values \tcode{k1} and \tcode{k2} are
21752175
considered equivalent if the container's
2176-
key equality predicate returns
2176+
key equality predicate
2177+
\tcode{pred(k1, k2)} is valid and returns
21772178
\tcode{true} when passed those values. If \tcode{k1} and
21782179
\tcode{k2} are equivalent, the container's hash function shall
21792180
return the same value for both.
@@ -2257,6 +2258,9 @@
22572258
\tcode{b} denotes a possibly const value of type \tcode{X},
22582259
\tcode{a_uniq} denotes a value of type \tcode{X} when \tcode{X} supports unique keys,
22592260
\tcode{a_eq} denotes a value of type \tcode{X} when \tcode{X} supports equivalent keys,
2261+
\tcode{a_tran} denotes a possibly const value of type \tcode{X}
2262+
when the \grammarterm{qualified-id} \tcode{X::hasher::transparent_key_equal}
2263+
is valid and denotes a type\iref{temp.deduct},
22602264
\tcode{i} and \tcode{j} denote input iterators that refer to \tcode{value_type},
22612265
\tcode{[i, j)} denotes a valid range,
22622266
\tcode{p} and \tcode{q2} denote valid constant iterators to \tcode{a},
@@ -2268,6 +2272,12 @@
22682272
\tcode{k} denotes a value of type \tcode{key_type},
22692273
\tcode{hf} denotes a possibly const value of type \tcode{hasher},
22702274
\tcode{eq} denotes a possibly const value of type \tcode{key_equal},
2275+
\tcode{ke} is a value such that
2276+
(1) \tcode{eq(r1, ke) == eq(ke, r1)}
2277+
with \tcode{r1} the key value of \tcode{e} and \tcode{e} in \tcode{a_tran},
2278+
(2) \tcode{hf(r1) == hf(ke)} if \tcode{eq(r1, ke)} is \tcode{true}, and
2279+
(3) \tcode{(eq(r1, ke) \&\& eq(r1, r2)) == eq(r2, ke)}
2280+
where \tcode{r2} is the key of an element in \tcode{a_tran},
22712281
\tcode{n} denotes a value of type \tcode{size_type},
22722282
\tcode{z} denotes a value of type \tcode{float},
22732283
and \tcode{nh} denotes a non-const rvalue of type \tcode{X::node_type}.
@@ -2327,7 +2337,9 @@
23272337
%
23282338
\indexunordmem{key_equal}%
23292339
\tcode{X::key_equal}
2330-
& \tcode{Pred}
2340+
& \tcode{Hash::transparent_key_equal} if such a \grammarterm{qualified-id}
2341+
is valid and denotes a type\iref{temp.deduct};
2342+
otherwise, \tcode{Pred}.
23312343
& \requires\ \tcode{Pred} is \oldconcept{CopyConstructible}.\br
23322344
\tcode{Pred} shall be a binary predicate that takes two arguments
23332345
of type \tcode{Key}. \tcode{Pred} is an equivalence relation.%
@@ -2721,20 +2733,43 @@
27212733
& Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}.
27222734
\\ \rowsep
27232735
%
2736+
\tcode{a_tran.find(ke)}
2737+
& \tcode{iterator}; \br \tcode{const_iterator} for const \tcode{a_tran}.
2738+
& Returns an iterator pointing to an element with key equivalent to
2739+
\tcode{ke}, or \tcode{a_tran.end()} if no such element exists.%
2740+
& Average case \bigoh{1},
2741+
worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid wverfull
2742+
\\ \rowsep
2743+
%
27242744
\indexunordmem{count}%
27252745
\tcode{b.count(k)}
27262746
& \tcode{size_type}
27272747
& Returns the number of elements with key equivalent to \tcode{k}.%
27282748
& Average case \bigoh{\tcode{b.count(k)}}, worst case \bigoh{\tcode{b.size()}}.
27292749
\\ \rowsep
27302750
%
2751+
\tcode{a_tran.count(ke)}
2752+
& \tcode{size_type}
2753+
& Returns the number of elements with key equivalent to \tcode{ke}.%
2754+
& Average case
2755+
\bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}, % avoid overfull
2756+
worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull
2757+
\\ \rowsep
2758+
%
27312759
\indexunordmem{contains}%
27322760
\tcode{b.contains(k)}
27332761
& \tcode{bool}
27342762
& Equivalent to \tcode{b.find(k) != b.end()}%
27352763
& Average case \bigoh{1}, worst case \bigoh{\tcode{b.size()}}.
27362764
\\ \rowsep
27372765
%
2766+
\tcode{a_tran.contains(ke)}
2767+
& \tcode{bool}
2768+
& Equivalent to \tcode{a_tran.find(ke) != a_tran.end()}%
2769+
& Average case \bigoh{1},
2770+
worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull
2771+
\\ \rowsep
2772+
%
27382773
\indexunordmem{equal_range}%
27392774
\tcode{b.equal_range(k)}
27402775
& \tcode{pair<iterator, iterator>}; \br
@@ -2746,6 +2781,16 @@
27462781
\bigoh{\tcode{b.size()}}.
27472782
\\ \rowsep
27482783
%
2784+
\tcode{a_tran.equal_range(ke)}
2785+
& \tcode{pair<iterator, iterator>}; \br
2786+
\tcode{pair<const_iterator, const_iterator>} for const \tcode{a_tran}.
2787+
& Returns a range containing all elements with keys equivalent to
2788+
\tcode{ke}. Returns \tcode{make_pair(a_tran.end(), a_tran.end())} if
2789+
no such elements exist.%
2790+
& Average case
2791+
\bigoh{\tcode{a_tran.}\br{}\tcode{count(ke)}}. % avoid overfull
2792+
Worst case \bigoh{\tcode{a_tran.}\br{}\tcode{size()}}. % avoid overfull
2793+
\\ \rowsep
27492794
\indexunordmem{bucket_count}%
27502795
\tcode{b.bucket_count()}
27512796
& \tcode{size_type}
@@ -2924,6 +2969,24 @@
29242969
obtained while it is owned by a \tcode{node_type} are invalidated if the
29252970
element is successfully inserted.
29262971

2972+
\pnum
2973+
If the \grammarterm{qualified-id} \tcode{Hash::transparent_key_equal}
2974+
is valid and denotes a type\iref{temp.deduct}.
2975+
then the program is ill-formed if either:
2976+
\begin{itemize}
2977+
\item
2978+
\grammarterm{qualified-id} \tcode{Hash::transparent_key_equal::is_transparent}
2979+
is not valid or does not denote a type, or
2980+
\item
2981+
\tcode{Pred} is a different type than \tcode{equal_to<Key>} or
2982+
\tcode{Hash::transparent_key_equal}.
2983+
\end{itemize}
2984+
The member function templates
2985+
\tcode{find}, \tcode{count}, \tcode{equal_range}, and \tcode{contains}
2986+
shall not participate in overload resolution unless
2987+
the \grammarterm{qualified-id} \tcode{Hash::transparent_key_equal}
2988+
is valid and denotes a type\iref{temp.deduct}.
2989+
29272990
\pnum
29282991
A deduction guide for an unordered associative container shall not participate in overload resolution
29292992
if any of the following are true:
@@ -7486,7 +7549,7 @@
74867549
using mapped_type = T;
74877550
using value_type = pair<const Key, T>;
74887551
using hasher = Hash;
7489-
using key_equal = Pred;
7552+
using key_equal = @\seeref{unord.req}@;
74907553
using allocator_type = Allocator;
74917554
using pointer = typename allocator_traits<Allocator>::pointer;
74927555
using const_pointer = typename allocator_traits<Allocator>::const_pointer;
@@ -7620,12 +7683,24 @@
76207683
key_equal key_eq() const;
76217684

76227685
// map operations
7623-
iterator find(const key_type& k);
7624-
const_iterator find(const key_type& k) const;
7625-
size_type count(const key_type& k) const;
7626-
bool contains(const key_type& k) const;
7627-
pair<iterator, iterator> equal_range(const key_type& k);
7628-
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
7686+
iterator find(const key_type& k);
7687+
const_iterator find(const key_type& k) const;
7688+
template <class K>
7689+
iterator find(const K& k);
7690+
template <class K>
7691+
const_iterator find(const K& k) const;
7692+
size_type count(const key_type& k) const;
7693+
template <class K>
7694+
size_type count(const K& k) const;
7695+
bool contains(const key_type& k) const;
7696+
template <class K>
7697+
bool contains(const K& k) const;
7698+
pair<iterator, iterator> equal_range(const key_type& k);
7699+
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
7700+
template <class K>
7701+
pair<iterator, iterator> equal_range(const K& k);
7702+
template <class K>
7703+
pair<const_iterator, const_iterator> equal_range(const K& k) const;
76297704

76307705
// \ref{unord.map.elem}, element access
76317706
mapped_type& operator[](const key_type& k);
@@ -8033,7 +8108,7 @@
80338108
using mapped_type = T;
80348109
using value_type = pair<const Key, T>;
80358110
using hasher = Hash;
8036-
using key_equal = Pred;
8111+
using key_equal = @\seeref{unord.req}@;
80378112
using allocator_type = Allocator;
80388113
using pointer = typename allocator_traits<Allocator>::pointer;
80398114
using const_pointer = typename allocator_traits<Allocator>::const_pointer;
@@ -8149,12 +8224,24 @@
81498224
key_equal key_eq() const;
81508225

81518226
// map operations
8152-
iterator find(const key_type& k);
8153-
const_iterator find(const key_type& k) const;
8154-
size_type count(const key_type& k) const;
8155-
bool contains(const key_type& k) const;
8156-
pair<iterator, iterator> equal_range(const key_type& k);
8157-
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8227+
iterator find(const key_type& k);
8228+
const_iterator find(const key_type& k) const;
8229+
template <class K>
8230+
iterator find(const K& k);
8231+
template <class K>
8232+
const_iterator find(const K& k) const;
8233+
size_type count(const key_type& k) const;
8234+
template <class K>
8235+
size_type count(const K& k) const;
8236+
bool contains(const key_type& k) const;
8237+
template <class K>
8238+
bool contains(const K& k) const;
8239+
pair<iterator, iterator> equal_range(const key_type& k);
8240+
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8241+
template <class K>
8242+
pair<iterator, iterator> equal_range(const K& k);
8243+
template <class K>
8244+
pair<const_iterator, const_iterator> equal_range(const K& k) const;
81588245

81598246
// bucket interface
81608247
size_type bucket_count() const noexcept;
@@ -8361,7 +8448,7 @@
83618448
using key_type = Key;
83628449
using value_type = Key;
83638450
using hasher = Hash;
8364-
using key_equal = Pred;
8451+
using key_equal = @\seeref{unord.req}@;
83658452
using allocator_type = Allocator;
83668453
using pointer = typename allocator_traits<Allocator>::pointer;
83678454
using const_pointer = typename allocator_traits<Allocator>::const_pointer;
@@ -8476,12 +8563,24 @@
84768563
key_equal key_eq() const;
84778564

84788565
// set operations
8479-
iterator find(const key_type& k);
8480-
const_iterator find(const key_type& k) const;
8481-
size_type count(const key_type& k) const;
8482-
bool contains(const key_type& k) const;
8483-
pair<iterator, iterator> equal_range(const key_type& k);
8484-
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8566+
iterator find(const key_type& k);
8567+
const_iterator find(const key_type& k) const;
8568+
template <class K>
8569+
iterator find(const K& k);
8570+
template <class K>
8571+
const_iterator find(const K& k) const;
8572+
size_type count(const key_type& k) const;
8573+
template <class K>
8574+
size_type count(const K& k) const;
8575+
bool contains(const key_type& k) const;
8576+
template <class K>
8577+
bool contains(const K& k) const;
8578+
pair<iterator, iterator> equal_range(const key_type& k);
8579+
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8580+
template <class K>
8581+
pair<iterator, iterator> equal_range(const K& k);
8582+
template <class K>
8583+
pair<const_iterator, const_iterator> equal_range(const K& k) const;
84858584

84868585
// bucket interface
84878586
size_type bucket_count() const noexcept;
@@ -8651,7 +8750,7 @@
86518750
using key_type = Key;
86528751
using value_type = Key;
86538752
using hasher = Hash;
8654-
using key_equal = Pred;
8753+
using key_equal = @\seeref{unord.req}@;
86558754
using allocator_type = Allocator;
86568755
using pointer = typename allocator_traits<Allocator>::pointer;
86578756
using const_pointer = typename allocator_traits<Allocator>::const_pointer;
@@ -8765,12 +8864,24 @@
87658864
key_equal key_eq() const;
87668865

87678866
// set operations
8768-
iterator find(const key_type& k);
8769-
const_iterator find(const key_type& k) const;
8770-
size_type count(const key_type& k) const;
8771-
bool contains(const key_type& k) const;
8772-
pair<iterator, iterator> equal_range(const key_type& k);
8773-
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8867+
iterator find(const key_type& k);
8868+
const_iterator find(const key_type& k) const;
8869+
template <class K>
8870+
iterator find(const K& k);
8871+
template <class K>
8872+
const_iterator find(const K& k) const;
8873+
size_type count(const key_type& k) const;
8874+
template <class K>
8875+
size_type count(const K& k) const;
8876+
bool contains(const key_type& k) const;
8877+
template <class K>
8878+
bool contains(const K& k) const;
8879+
pair<iterator, iterator> equal_range(const key_type& k);
8880+
pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
8881+
template <class K>
8882+
pair<iterator, iterator> equal_range(const K& k);
8883+
template <class K>
8884+
pair<const_iterator, const_iterator> equal_range(const K& k) const;
87748885

87758886
// bucket interface
87768887
size_type bucket_count() const noexcept;

source/macros.tex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@
296296
\newcommand{\unspecbool}{\UNSP{unspecified-bool-type}}
297297
\newcommand{\seebelow}{\UNSP{see below}}
298298
\newcommand{\seebelownc}{\UNSPnc{see below}}
299+
\newcommand{\seeref}[1]{\UNSP{see~\ref{#1}}}
300+
\newcommand{\seerefnc}[1]{\UNSPnc{see~\ref{#1}}}
299301
\newcommand{\unspecuniqtype}{\UNSP{unspecified unique type}}
300302
\newcommand{\unspecalloctype}{\UNSP{unspecified allocator type}}
301303

0 commit comments

Comments
 (0)