Document number: P0433R2
Date: 2017-03-03
Reply-To:
Mike Spertus, Symantec (mike_spertus@symantec.com)
Walter E. Brown ( webrown.cpp@gmail.com)
Stephan T. Lavavej (stl@exchange.microsoft.com)
Audience: {Library Evolution, Library} Working Group
National body comments US7 and US14 request analysis of the standard library to determine what changes might be desirable in light of the C++17 adoption of P0091R3 (Template argument deduction for class templates (rev. 6)). In this paper, we perform such an analysis and recommend wording changes for the standard library clauses.
string needle = "foo";
auto bms = boyer_moore_searcher(needle.begin(), needle.end());
gamma_distribution gdf{2.5f, .7f};
while heavily-metaprogrammed STL classes (e.g., vector) generally require some explicit deduction guides but
that generally proved straightforward. Adapting the entire standard library took about 40 hours, most of which was
spent on writing test cases.optional o(3); // Deduces optional<int>
optional o2 = o; // Deduces optional<int>
template<typename T> void foo(T t)
{
optional o = t; // T=optional<int> => o is optional<int>, which may not be desired in generic code
optional<T> o2 = t; // o2 is optional<optional<int>>
}
We feel this is the right tradeoff as application programmers consuming template libraries get full benefit
of deduction and template library writers are not worse off than in C++14. P0091R4 suggests a language
extension to extend deduction to the example above. However, note that this does not impact the present proposal.This clause requires no deduction guides because it specifies only C libraries and so no class templates are involved.
- an explicit or partial specialization of any member class template of a standard library class or class template.
- a deduction guide for any standard library class template.
Rationale: All of the headers in §18 are listed in “Table 30 — Language support library summary” in §18.1 [support.general]:
Subclause | Header(s) | |
---|---|---|
18.2 | Common definitions | <cstddef> |
18.3 | Implementation properties | <limits> <climits> <cfloat> |
18.4 | Integer types | <cstdint> |
18.5 | Start and termination | <cstdlib> |
18.6 | Dynamic memory management | <new> |
18.7 | Type identification | <typeinfo> |
18.8 | Exception handling | <exception> |
18.9 | Initializer lists | <initializer_list> |
18.10 | Other runtime support | <csignal> <csetjmps> <cstdalign> <cstdarg> <cstdbool> <cstdlib> |
Rationale: All of the headers in §19 are listed in “Table 31 — Diagnostics library summary” in §19.1:
Subclause | Header(s) | |
---|---|---|
19.2 | Exception classes | <stdexcept> |
19.3 | Assertions | <cassert> |
19.4 | Error numbers | <cerrno> |
19.5 | System error support | <system_error> |
None of these define any class templates, so they are unaffected by template constructor deduction.
This header defines the class templates is_error_code_enum, is_error_condition_enum, and specializations of std::hash, all of which have only default constructors.
Subclause | Header(s) | |
---|---|---|
20.2 | Utilities components | <utility> |
20.3 | Compile-time integer sequences | <utility> |
20.4 | Pairs | <utility> |
20.5 | Tuples | <tuple> |
20.6 | Optional objects | <optional> |
20.7 | Variants | <variant> |
20.8 | Storage for any type | <any> |
20.9 | Fixed-size sequences of bits | <bitset> |
20.10 | Memory | <memory> <cstdlib> |
20.11 | Smart pointers | <memory> |
20.12 | Memory resources | <memory_resource> |
20.13 | Scoped allocators | <scoped_allocator> |
20.14 | Function objects | <functional> |
20.15 | Type traits | <type_traits> |
20.16 | Compile-time rational arithmetic | <ratio> |
20.17 | Time utilities | <chrono> <ctime> |
20.18 | Type indexes | <typeindex> |
20.19 | Execution policies | <execution> |
Make the following change to the definition of std::pair in §20.4.2 [pairs.pair]:
void swap(pair& p) noexcept(see below);
};
template<class T1, class T2>
pair(T1, T2) -> pair<T1, T2>;
}
void swap(tuple&) noexcept(see below);
};
template<class... UTypes>
tuple(UTypes...) -> tuple<UTypes...>;
template<class T1, class T2>
tuple(pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, UTypes...) -> tuple<UTypes...>;
template<class Alloc, class T1, class T2>
tuple(allocator_arg_t, Alloc, pair<T1, T2>) -> tuple<T1, T2>;
template<class Alloc, class... UTypes>
tuple(allocator_arg_t, Alloc, tuple<UTypes...>) -> tuple<UTypes...>;
}
Note: See the Background above for additional discussion of optional.T *val; // exposition only }; template<class T> optional(T) -> optional<T>;
int *ip = new int();
unique_ptr uip{ip}; // Deduce unique_ptr<int>
On the positive side, the code is natural, useful (although not at object creation, when make_unique is
preferable), and we have already received
a request from the community for it. The downside is that it will fail to deduce an array type
int *ip = new int[5];
unique_ptr uip{ip}; // Still deduces unique_ptr<int>
We choose not to allow this problem, so we require that such deductions be ill-formed. Modify §20.11.1.2.1p8 [unique.ptr.single.ctor] as follows:
Remarks: If this constructor is instantiated with a pointer type or reference type for the template argument D, the program is ill-formed. If class template argument deduction (13.3.1.8) would select the function template corresponding to this constructor, then the program is ill-formed.Add the following paragraph after §20.11.1.2.1p14 [unique.ptr.single.ctor]:
Remarks:If class template argument deduction (13.3.1.8) would select a function template corresponding to either of these constructors, then the program is ill-formed.We handle shared_ptr the same as unique_ptr. Because the an implicit guides from T * are non-deducible, we do not need to add special wording for those constructors. We do not include a guide for the aliasing constructor as unnecessary.
Make the following modifications to §20.11.2.2 [util.smartptr.shared]:
template<class U> bool owner_before(const shared_ptr<U>& b) const;
template<class U> bool owner_before(const weak_ptr<U>& b) const;
};
template <class T> shared_ptr(weak_ptr<T>) -> shared_ptr<T>;
template <class T, class D> shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>;
For weak_ptr, make the following modification to §20.11.2.3 [util.smartptr.weak]
template<class U> bool owner_before(const weak_ptr<U>& b) const;
};
template<class T> weak_ptr(shared_ptr<T>) -> weak_ptr<T>;
For completeness, owner_less relies on implicit deduction guides. enable_shared_from_this does not really require any guides, but the implicit ones certainly do no harm.
scoped_allocator_adaptor select_on_container_copy_construction() const;
};
template<class OuterAlloc, class... InnerAllocs> scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
-> scoped_allocator_adaptor<OuterAllocator, InnerAllocs...>;
If a different outer allocator is desired, then
it can still be specified explicitly.
operator() (ArgTypes&&...) const;
};
template<typename T>
reference_wrapper(reference_wrapper<T>) -> reference_wrapper<T>;
We suggest allowing function to deduce its template argument when initialized
by a function. While it is tempting to add deduction guides for member pointers,
we no longer do so as there is a question about whether the first objects
should be a pointer or a reference. We are interested in committee feedback.
Note that we can always add this post-c++17.Add the following deduction guide at the end of the
class definition for function in §20.14.12.2 [func.wrap.func]
template<class T> const T* target() const noexcept;
};
template<class R, class... ArgTypes>
function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;
template<class F>
function(F) -> function<see below>;
Add a paragraph after §20.14.13.2.1p11 [func.wrap.func.con]
Add a new paragraph after 20.14.13.2p3 [func.wrap.func]:template<class F> function(F) -> function<see below>;
Remarks:This deduction guide participates in overload resolution only if &F::operator() is well-formed when treated as an unevaluated operand. In that case, if decltype(&F::operator()) is of the form R(G::*)(A...) cv &opt noexceptopt for a class type G, then the deduced type shall be function<R(A...)>.[Example:—end example]void f() { int i{5}; function g = [&](double) { return i; }; // Deduces function<int(double)> }
[ Note: The types deduced by the deduction guides for function may change in future versions of this International Standard. —end note]Note: There are some arbitrary choices in the deductions for member pointers. We would be interested to see if the comittee agrees with having deduction guides for member pointers in addition to function pointers, and if so, whether these are the right choices.
Since template constructor deduction can be used to construct objects of type default_searcher, boyer_moore_searcher, and boyer_moore_horspool_searcher, we propose getting rid of the searcher creation functions by modifying §20.14p2 as follows:
Delete §20.14.13.1.1 [func.searchers.default.creation]// 20.14.13 searchers: template<class ForwardIterator, class BinaryPredicate = equal_to<>> class default_searcher; template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> class boyer_moore_searcher; template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> class boyer_moore_horspool_searcher; template<class ForwardIterator, class BinaryPredicate = equal_to<>> default_searcher<ForwardIterator, BinaryPredicate> make_default_searcher(ForwardIterator pat_first, ForwardIterator pat_last, BinaryPredicate pred = BinaryPredicate()); template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate> make_boyer_moore_searcher( RandomAccessIterator pat_first, RandomAccessIterator pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate()); template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate> make_boyer_moore_horspool_searcher( RandomAccessIterator pat_first, RandomAccessIterator pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate()); // 20.14.14, hash function primary template:
2014.13.2.1 boyer_moore_searcher creation functions [func.searcher.boyer_moore.creation]Delete §20.14.13.2.1 [func.searchers.boyer_moore.creation]template<class ForwardIterator, class BinaryPredicate = equal_to<>> default_searcher<ForwardIterator, BinaryPredicate> make_default_searcher(ForwardIterator pat_first, RandomAccessIterator pat_last, BinaryPredicate pred = BinaryPredicate());
Effects: Equivalent to:return default_searcher<ForwardIterator, BinaryPredicate>(pat_first, pat_last, pred);
2014.13.2.1 boyer_moore_searcher creation functions [func.searcher.boyer_moore.creation]Delete §20.14.13.3.1 [func.searchers.boyer_moore_horspool.creation]template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate> make_boyer_moore_searcher( RandomAccessIterator pat_first, RandomAccessIterator pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());
Effects: Equivalent to:return boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate>( pat_first, pat_last, hf, pred);
2014.13.2.1 boyer_moore_searcher creation functions [func.searcher.boyer_moore.creation]template<class RandomAccessIterator, class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, class BinaryPredicate = equal_to<>> boyer_moore_horspool_searcher<RandomAccessIterator, Hash, BinaryPredicate> make_boyer_moore_horspool_searcher( RandomAccessIterator pat_first, RandomAccessIterator pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());
Effects: Equivalent to:return boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate>( pat_first, pat_last, hf, pred);
It is worth noting that a library vendor may
choose to make additional deduction guides in accordance with the “as-if”
rule (§1.9 footnote 5) as illustrated by the following example. Suppose
a vendor has previously leveraged the
“as-if” rule to implement the constructor
basic_string<charT, traits, Allocator>::basic_string(const charT* str, const Allocator& a = Allocator());
using the equivalent but non-deducible type value_type in place of charT
as follows:
basic_string<charT, traits, Allocator>::basic_string(const value_type* str, const Allocator& a = Allocator());
The vendor could maintain this convention while continuing to satisfy the “as-if” rule in C++17
by adding the following deduction-guide to their implementation:
template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
basic_string(const charT*, Allocator = Allocator()) -> basic_string<charT, Allocator>;
Add the following after the end of the definition of class basic_string in §21.3.2 [basic.string]
int compare(size_type pos1, size_type n1,
const charT* s, size_type n2) const;
};
template<class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
basic_string(InputIterator, InputIterator, Allocator = Allocator())
-> basic_string<typename iterator_traits<InputIterator>::value_type,
char_traits<typename iterator_traits<InputIterator>::value_type>, Allocator>;
In §21.3.2.2 [string.cons], insert the following between paragraphs 19 and 20:
template<class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>> basic_string(InputIterator, InputIterator, Allocator = Allocator()) -> basic_string<typename iterator_traits<InputIterator>::value_type, char_traits<typename iterator_traits<InputIterator>::value_type>, Allocator>;
Remarks: Shall not participate in overload resolution if InputIterator is a type that does not qualify as an input iterator, or if Allocator is a type that does not qualify as an allocator [sequence.reqmts].
Subclause | Header(s) | |
---|---|---|
23.2 | Requirements | |
23.3 | Sequence containers | <array> <deque> <forward_list> <list> <vector> |
23.4 | Associative containers | <map> <set> |
23.5 | Unordered associative containers | <unordered_map> <unordered_set> |
23.6 | Container adaptors | <queue> <stack> |
are called with a type InputIterator that does not qualify as an input iterator, then those functions shall not participare in overload resolution.Add a paragraph to the end of §23.2.6 [associative.reqmts]— A deduction guide for a sequence container shall not participate in overload resolution if it has an InputIterator template parameter that is called with a type that does not qualify as an input iterator, or if it has an Allocator template parameter that is called with a type that does not qualify as an allocator.
The extent to which an implementation determines that a type cannot be an input iterator is unspecified, except that as a minimum integral types shall not qualify as input iterators. Likewise, the extent to which an implementation determines that a type cannot be an allocator is unspecified, except that as a minimum a type A not satisfying both of the following conditions shall not qualify as an allocator:
- The qualified-id A::value_type is valid and denotes a type [temp.deduct]
- The expression declval<A&>().allocate(size_t{}) is well-formed when treated as an unevaluated operand
Add a paragraph to the end of §23.2.7 [unord.req]A deduction guide for an associative container shall not participate in overload resolution if any of the following are true:
- It has an InputIterator template parameter that is called with a type that does not qualify as an input iterator
- It has an Allocator template parameter that is called with a type that does not qualify as an allocator
- It has a Compare template parameter that is called with a type that qualifies as an allocator
Note: The reason to ensure that Hash is not integral is to keep it from matching the size_type that some constructors use to specify the number of hash buckets.A deduction guide for an unordered associative container shall not participate in overload resolution if any of the following are true:
- It has an InputIterator template parameter that is called with a type that does not qualify as an input iterator
- It has an Allocator template parameter that is called with a type that does not qualify as an allocator
- It has a Hash template parameter that is called with an integral type or a type that qualifies as an allocator
- It has a Pred template parameter that is called with a type that qualifies as an allocator
constexpr const T * data() const noexcept;
};
template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
}
Add the following paragraph to the end of 23.3.7.2 [array.cons]
template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
Requires:
(is_same_v<T, U> && ...) is true. Otherwise
the program is ill-formed.
At the end of the definition of class deque in §23.3.8.1 [deque.overview],
add the following deduction-guide:
void clear() noexcept;
};
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
deque(InputIterator, InputIterator, Allocator = Allocator())
-> deque<typename iterator_traits<InputIterator>::value_type, Allocator>;
At the end of the definition of class forward_list in §23.3.9.1 [forwardlist.overview],
add the following deduction-guide:
void reverse() noexcept;
};
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
forward_list(InputIterator, InputIterator, Allocator = Allocator())
-> forward_list<typename iterator_traits<InputIterator>::value_type, Allocator>;
At the end of the definition of class list in §23.3.10.1 [list.overview],
add the following deduction-guides:
void reverse() noexcept;
};
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
list(InputIterator, InputIterator, Allocator = Allocator())
-> list<typename iterator_traits<InputIterator>::value_type, Allocator>;
At the end of the definition of class vector in §23.3.11.1 [vector.overview],
add the following deduction-guide:
void clear() noexcept;
};
template <class InputIterator, class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
vector(InputIterator, InputIterator, Allocator = Allocator())
-> vector<typename iterator_traits<InputIterator>::value_type, Allocator>;
Note that with the above guides vector<bool> behaves properly as well.
map m = {{"foo", 2}, {"bar", 3}, {"baz", 4}}; // Error: initializer_list not reified in type system
map m2 = initializer_list<pair<char const *, int>>({{"foo", 2}, {"bar", 3}, {"baz", 4}}); // OK
Hopefully, this may be addressed by a future language extension in the post-C++17 timeline. Note also
that we apply remove_const_t to the keys in order to find the proper comparator (or hash in case
of unordered containers).Add a paragraph to §23.4.1 [associative.general]
The following exposition only type aliases may appear in deduction guides for associative containers:At the end of the definition of class map in §23.4.4.1 [map.overview], add the following deduction-guides:template<class InputIterator> using iter_key_t = remove_const_t<typename iterator_traits<InputIterator>::value_type::first_type>; // exposition only template<class InputIterator> using iter_val_t = typename iterator_traits<InputIterator>::value_type::second_type; // exposition only template<class InputIterator> using iter_to_alloc_t = pair<add_const_t<typename iterator_traits<InputIterator>::value_type::first_type>, typename iterator_traits<InputIterator>::value_type::second_type> // exposition only
template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
template <class InputIterator,
class Compare = less<iter_key_t<InputIterator>>,
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
map(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
-> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>;
template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>>
map(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
-> map<Key, T, Compare, Allocator>;
template <class InputIterator, class Allocator>
map(InputIterator, InputIterator, Allocator)
-> map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, less<iter_key_t<InputIterator>>, Allocator>;
template<class Key, class T, class Allocator>
map(initializer_list<pair<const Key, T>>, Allocator) -> map<Key, T, less<Key>, Allocator>;
At the end of the definition of class multimap in §23.4.5.1 [multimap.overview],
add the following deduction-guides:
template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
template <class InputIterator,
class Compare = less<iter_key_t<InputIterator>>,
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
multimap(InputIterator, InputIterator, Compare = Compare(), Allocator = Allocator())
-> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Compare, Allocator>;
template<class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key, T>>>
multimap(initializer_list<pair<const Key, T>>, Compare = Compare(), Allocator = Allocator())
-> multimap<Key, T, Compare, Allocator>;
template <class InputIterator, class Allocator>
multimap(InputIterator, InputIterator, Allocator)
-> multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, less<iter_key_t<InputIterator>>, Allocator>;
template<class Key, class T, class Allocator>
multimap(initializer_list<pair<const Key, T>>, Allocator) -> multimap<Key, T, less<Key>, Allocator>;
At the end of the definition of class set in §23.4.6.1 [set.overview],
add the following deduction-guides:
template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
template <class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
set(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
template<class InputIterator, class Allocator>
set(InputIterator, InputIterator, Allocator)
-> set<typename iterator_traits<InputIterator>::value_type,
less<typename iterator_traits<InputIterator>::value_type>, Allocator>;
template<class Key, class Allocator>
set(initializer_list<Key>, Allocator) -> set<Key, less<Key>, Allocator>;
At the end of the definition of class multiset in §23.4.7.1 [multiset.overview],
add the following deduction-guide:
template <class K>
pair<const_iterator, const_iterator> equal_range(const K& x) const;
};
template <class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
multiset(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> multiset<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
multiset(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> multiset<Key, Compare, Allocator>;
template<class InputIterator, class Allocator>
multiset(InputIterator, InputIterator, Allocator)
-> multiset<typename iterator_traits<InputIterator>::value_type,
less<typename iterator_traits<InputIterator>::value_type>, Allocator>;
template<class Key, class Allocator>
multiset(initializer_list<Key>, Allocator) -> multiset<Key, less<Key>, Allocator>;
The exposition only type aliases iter_key_t, iter_val_t, and iter_to_alloc_t defined in [associative.general] may appear in deduction guides for unordered containersAt the end of the definition of class unordered_map in §23.5.4.1 [unord.map.overview], add the following deduction-guides:
void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>,
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
unordered_map(InputIterator, InputIterator, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred, Allocator>;
template<class Key, class T, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_map<Key, T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_map(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class InputIterator, class Allocator>
unordered_map(InputIterator, InputIterator, Allocator)
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_map(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash,
equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class Key, class T, typename Allocator>
unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator)
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, typename Allocator>
unordered_map(initializer_list<pair<const Key, T>>, Allocator)
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Hash, class Allocator>
unordered_map(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash, Allocator)
-> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
Add the following paragraph to the end of §23.5.4.1 [unord.map.overview]:
A size_type parameter type in an unordered_map deduction guide refers to the size_type member type of the type deduced by the deduction guide.At the end of the definition of class unordered_multimap in §23.5.5.1 [unord.multimap.overview], add the following deduction-guides
void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<iter_key_t<InputIterator>>, class Pred = equal_to<iter_key_t<InputIterator>>,
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
unordered_multimap(InputIterator, InputIterator, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<iter_key_t<InputIterator>, iter_value_t<InputIterator>, Hash, Pred, Allocator>;
template<class Key, class T, class Hash = hash<Key>,
class Pred = equal_to<Key>, class Allocator = allocator<pair<const Key, T>>>
unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class InputIterator, class Allocator>
unordered_multimap(InputIterator, InputIterator, Allocator)
-> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
hash<iter_key_t<InputIterator>>, equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_multimap(InputIterator, InputIterator, typename see below::size_type, Hash, Allocator)
-> unordered_multimap<iter_key_t<InputIterator>, iter_val_t<InputIterator>, Hash,
equal_to<iter_key_t<InputIterator>>, Allocator>;
template<class Key, class T, typename Allocator>
unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Allocator)
-> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, typename Allocator>
unordered_multimap(initializer_list<pair<const Key, T>>, Allocator)
-> unordered_multimap<Key, T, hash<Key>, equal_to<Key>, Allocator>;
template<class Key, class T, class Hash, class Allocator>
unordered_multimap(initializer_list<pair<const Key, T>>, typename see below::size_type, Hash, Allocator)
-> unordered_multimap<Key, T, Hash, equal_to<Key>, Allocator>;
Add the following paragraph to the end of §23.5.5.1 [unord.multimap.overview]:
A size_type parameter type in an unordered_multimap deduction guide refers to the size_type member type of the type deduced by deduction guide.At the end of the definition of class unordered_set in §23.5.6.1 [unord.set.overview], add the following deduction-guides:
void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<typename iterator_traits<InputIterator>::value_type>,
class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
unordered_set(InputIterator, InputIterator, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<typename iterator_traits<InputIterator>::value_type,
Hash, Pred, Allocator>;
template<class T, class Hash = hash<T>,
class Pred = equal_to<T>, class Allocator = allocator<T>>
unordered_set(initializer_list<T>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_set<T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_set(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_set<typename iterator_traits<InputIterator>::value_type,
hash<typename iterator_traits<InputIterator>::value_type>,
equal_to<typename iterator_traits<InputIterator>::value_type>,
Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_set(InputIterator, InputIterator, typename see below::size_type,
Hash, Allocator)
-> unordered_set<typename iterator_traits<InputIterator>::value_type, Hash,
equal_to<typename iterator_traits<InputIterator>::value_type>,
Allocator>;
template<class T, class Allocator>
unordered_set(initializer_list<T>, typename see below::size_type, Allocator)
-> unordered_set<T, hash<T>, equal_to<T>, Allocator>;
template<class T, class Hash, class Allocator>
unordered_set(initializer_list<T>, typename see below::size_type, Hash, Allocator)
-> unordered_set<T, Hash, equal_to<T>, Allocator>;
Add the following paragraph to the end of §23.5.6.1 [unord.set.overview]:
A size_type parameter type in an unordered_set deduction guide refers to the size_type member type of the primary unordered_set template.At the end of the definition of class unordered_multiset in §23.5.7.1 [unord.multiset.overview], add the following deduction-guides:
void reserve(size_type n);
};
template<class InputIterator,
class Hash = hash<typename iterator_traits<InputIterator>::value_type>,
class Pred = equal_to<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
unordered_multiset(InputIterator, InputIterator, see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<typename iterator_traits<InputIterator>::value_type,
Hash, Pred, Allocator>;
template<class T, class Hash = hash<T>,
class Pred = equal_to<T>, class Allocator = allocator<T>>
unordered_multiset(initializer_list<T>, typename see below::size_type = see below,
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
-> unordered_multiset<T, Hash, Pred, Allocator>;
template<class InputIterator, class Allocator>
unordered_multiset(InputIterator, InputIterator, typename see below::size_type, Allocator)
-> unordered_multiset<typename iterator_traits<InputIterator>::value_type,
hash<typename iterator_traits<InputIterator>::value_type>,
equal_to<typename iterator_traits<InputIterator>::value_type>,
Allocator>;
template<class InputIterator, class Hash, class Allocator>
unordered_multiset(InputIterator, InputIterator, typename see below::size_type,
Hash, Allocator)
-> unordered_multiset<typename iterator_traits<InputIterator>::value_type, Hash,
equal_to<typename iterator_traits<InputIterator>::value_type>, Allocator>;
template<class T, class Allocator>
unordered_multiset(initializer_list<T>, typename see below::size_type, Allocator)
-> unordered_multiset<T, hash<T>, equal_to<T>, Allocator>;
template<class T, class Hash, class Allocator>
unordered_multiset(initializer_list<T>, typename see below::size_type, Hash, Allocator)
-> unordered_multiset<T, Hash, equal_to<T>, Allocator>;
Add the following paragraph to the end of §23.5.7.1 [unord.multiset.overview]:
A size_type parameter type in an unordered_multiset deduction guide refers to the size_type member type of the primary unordered_multiset template.
At the end of the definition of class queue in §23.6.4.1 [queue.defn] insertA deduction guide for a container adaptor shall not participate in overload resolution if any of the following are true:
- It has an InputIterator template parameter that is called with a type that does not qualify as an input iterator
- It has a Compare template parameter that is called with a type that qualifies as an allocator
- It has a Container template parameter that is called with a type that qualifies as an allocator
- It has an Allocator template parameter that is called with a type that does not qualify as an allocator
- It has both Container and Allocator template parameters, and uses_allocator_v<Container, Allocator> is false
void swap(queue& q) noexcept(is_nothrow_swappable_v<Container>)
{ using std::swap; swap(c, q.c); }
};
template<class Container>
queue(Container) -> queue<typename Container::value_type, Container>;
template<class Container, class Allocator>
queue(Container, Allocator) -> queue<typename Container::value_type, Container>;
At the end of the definition of class priority_queue in §23.6.5
[priority.queue], add the following deduction-guides:
void swap(priority_queue& q) noexcept(is_nothrow_swappable_v<Container> && is_nothrow_swappable_v<Compare>) { using std::swap; swap(c, q.c); swap(comp, q.comp); } };
template <class Compare, class Container>
priority_queue(Compare, Container)
-> priority_queue<typename Container::value_type, Container, Compare>;
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Container = vector<typename iterator_traits<InputIterator>::value_type>>
priority_queue(InputIterator, InputIterator, Compare = Compare(), Container = Container())
-> priority_queue<typename iterator_traits<InputIterator>::value_type, Container, Compare>;
template<class Compare, class Container, class Allocator>
priority_queue(Compare, Container, Allocator)
-> priority_queue<typename Container::value_type, Container, Compare>;
At the end of the definition of class stack in §23.6.6.1 [stack.defn], add
void swap(stack& q) noexcept(is_nothrow_swappable_v<Container>)
{ using std::swap; swap(c, q.c); }
};
template<class Container>
stack(Container) -> stack<typename Container::value_type, Container>;
template<class Container, class Allocator>
stack(Container, Allocator) -> stack<typename Container::value_type, Container>;
int iar[] = {1, 2, 3};
int *ip = iarr;
valarray va(ip, 3); // Deduces valarray<int>
The point is that the valarray<T>::valarray(const T *, size_t) constructor is a better match
than the valarray<T>::valarray(const T &, size_t) constructor. We think this is preferable
because we believe that is the much more common default. Note that P0091R4 discusses a language extension (= delete
for the valarray(const T *, size_t) deduction guide) that would facilitate suppressing deduction in this case.
However, as above, we believe the appropriate deduction is produced by the implicitly-generated deduction guides.
We do add a deduction guide to enable the following deduction:
int iarr[] = {1, 2, 3};
valarray va(iarr, 3); // Needs explicit deduction guide to deduce valarray<int>
At the end of the definition of class valarray in §26.7.2.1 [template.valarray.overview], insert the following
void resize(size_t sz, T c = T());
};
template<typename T, size_t cnt> valarray(const T(&)[cnt], size_t) -> valarray<T>;
// 28.8.6, swap void swap(basic_regex&); }; template<class ForwardIterator> basic_regex(ForwardIterator, ForwardIterator, regex_constants::syntax_option_type = regex_constants::ECMAScript) -> basic_regex<typename iterator_traits<ForwardIterator>::value_type>;
};
template<class M> lock_guard(lock_guard<M>) -> lock_guard<M>;
At the end of the definition class scoped_lock in [thread.lock.scoped], add
};
template<class... M> scoped_lock(scoped_lock<M...>) -> scoped_lock<M...>;
At the end of the definition class unique_lock in [thread.lock.unique], add
};
template<class M> unique_lock(unique_lock<M>) -> unique_lock<M>;
At the end of the definition class shared_lock in [thread.lock.shared], add
};
template<class M> shared_lock(shared_lock<M>) -> shared_lock<M>;