Section: 16.4.5.2.1 [namespace.std] Status: C++23 Submitter: Michael Park Opened: 2020-05-08 Last modified: 2023-11-22
Priority: 1
View other active issues in [namespace.std].
View all other issues in [namespace.std].
View all issues with C++23 status.
Discussion:
P0551 (Thou Shalt Not Specialize std
Function Templates!)
added a clause in [namespace.std]/7:
Other than in namespace
std
or in a namespace within namespacestd
, a program may provide an overload for any library function template designated as a customization point, provided that (a) the overload's declaration depends on at least one user-defined type and (b) the overload meets the standard library requirements for the customization point. (footnote 174) [Note: This permits a (qualified or unqualified) call to the customization point to invoke the most appropriate overload for the given arguments. — end note]
Given that std::swap
is a designated customization point, the note seems to suggest the following:
namespace N {
struct X {};
void swap(X&, X&) {}
}
N::X a, b;
std::swap(a, b); // qualified call to customization point finds N::swap?
This is not what happens, as the call to std::swap
does not find N::swap
.
[2020-07-17; Priority set to 1 in telecon]
Related to 3442.
[2020-09-11; discussed during telecon]
The note is simply bogus, not backed up by anything normative.
The normative part of the paragraph is an unacceptable landgrab on those
identifiers.
We have no right telling users they can't use the names data
and size
unless they do exactly what we say std::data
and std::size
do.
The library only ever uses swap
unqualified, so the effect of
declaring the others as designated customization points is unclear.
The rule only needs to apply to such overloads when actually found by overload resolution in a context that expects the semantics of the customization point.
Frank: do we need to designate operator<<
as a
customization point? Users overload that in their own namespaces all the time.
Walter: This clearly needs a paper.
[2020-10-02; status to Open]
Previous resolution [SUPERSEDED]:
This wording is relative to N4861.
Modify 16.4.5.2.1 [namespace.std] as indicated:
-7- Other than in namespace
std
or in a namespace within namespacestd
, a program may provide an overload for any library function template designated as a customization point, provided that (a) the overload's declaration depends on at least one user-defined type and (b) the overload meets the standard library requirements for the customization point. (footnote 173)[Note: This permits a (qualified or unqualified) call to the customization point to invoke the most appropriate overload for the given arguments. — end note]
[Issaquah 2023-02-09; Jonathan provides improved wording]
The normative part of 16.4.5.2.1 [namespace.std] paragraph 7
(i.e. not the note and the footnote) does not actually do anything
except tell users they're not allowed to use the names
begin
, size
etc. unless they conform to the
provisions of paragraph 7. This means a program that contains the
following declaration might have undefined behaviour:
namespace user { int data(int, int); }
This is not OK! It's not even clear what "the requirements for
the customization point" are, if users wanted to meet them.
It's not even clear what "provide an overload" means.
In particular, paragraph 7 does not give permission for the
designated customization points to actually use such
overloads. Just by forbidding users from using data
for their own functions isn't sufficient to allow the library to
use ADL to call data
, and it's unclear why we'd want
that anyway (what problem with std::data
are we trying
to solve that way?). As shown in LWG 3442, if
std::data
became a customization point that would be
a backwards-incompatible change, and create a portability problem
if some implementations did that and others didn't.
So the non-normative note and footnote make claims that do not follow from the normative wording, and should be removed.
The only one of the designated customization points that
is actually looked up using ADL is std::swap
, but how that
works is fully specified by 16.4.2.2 [contents] and
16.4.4.3 [swappable.requirements]. The additional specification
that it's a designated customization point serves no benefit.
In particular, the permission that the note and footnote claim
exists is not needed. We specify precisely how swap
calls are performed.
We don't even need to say that user overloads of swap
in their own namespaces must meet the library requirements,
because the "swappable with" and Cpp17Swappable requirements
state the required semantics, and functions that use swap
have preconditions that the types are swappable. So we correctly
impose preconditions in the places that actually call swap,
and don't need to globally make it undefined for any function
called swap
to not meet the requirements, even if that
function is never found by ADL by the library (e.g. because it's
in a namespace that is never an associated namespace of any types
used with library components that require swappable types).
Paragraph 7 and its accompanying notes should go.
[Issaquah 2023-02-09; LWG]
Move to Immediate for C++23
[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate → WP.]
Proposed resolution:
This wording is relative to N4928.
Modify 16.4.5.2.1 [namespace.std] as indicated:
[Drafting note: This should also remove the only index entry for "customization point". ]
-7- Other than in namespacestd
or in a namespace within namespacestd
, a program may provide an overload for any library function template designated as a customization point, provided that (a) the overload's declaration depends on at least one user-defined type and (b) the overload meets the standard library requirements for the customization point. 163
[Note 3: This permits a (qualified or unqualified) call to the customization point to invoke the most appropriate overload for the given arguments. — end note]
163) Any library customization point must be prepared to work adequately with any user-defined overload that meets the minimum requirements of this document. Therefore an implementation can elect, under the as-if rule (6.9.1 [intro.execution]), to provide any customization point in the form of an instantiated function object (22.10 [function.objects]) even though the customization point's specification is in the form of a function template. The template parameters of each such function object and the function parameters and return type of the object'soperator()
must match those of the corresponding customization point's specification.
Modify 22.2.2 [utility.swap] as indicated:
template<class T> constexpr void swap(T& a, T& b) noexcept(see below);
-1- Constraints:
is_move_constructible_v<T>
istrue
andis_move_assignable_v<T>
istrue
.-2- Preconditions: Type
T
meets the Cpp17MoveConstructible (Table 32) and Cpp17MoveAssignable (Table 34) requirements.-3- Effects: Exchanges values stored in two locations.
-4- Remarks:
This function is a designated customization point (16.4.5.2.1 [namespace.std]).The exception specification is equivalent to:is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<T>
Modify 24.7 [iterator.range] as indicated:
-1- In addition to being available via inclusion of the <iterator> header, the function templates in 24.7 [iterator.range] are available when any of the following headers are included: <array> (23.3.2 [array.syn]), <deque> (23.3.4 [deque.syn]), <forward_list> (23.3.6 [forward.list.syn]), <list> (23.3.8 [list.syn]), <map> (23.4.2 [associative.map.syn]), <regex> (28.6.3 [re.syn]), <set> (23.4.5 [associative.set.syn]), <span> (23.7.2.1 [span.syn]), <string> (27.4.2 [string.syn]), <string_view> ( [string.view.syn]), <unordered_map> (23.5.2 [unord.map.syn]), <unordered_set> (23.5.5 [unord.set.syn]), and <vector> (23.3.10 [vector.syn]).
Each of these templates is a designated customization point (16.4.5.2.1 [namespace.std]).