Swappable
in terms of CopyConstructible
and Assignable
Section: 16.4.4.2 [utility.arg.requirements] Status: Resolved Submitter: Niels Dekker Opened: 2006-11-02 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [utility.arg.requirements].
View all issues with Resolved status.
Discussion:
It seems undesirable to define the Swappable
requirement in terms of
CopyConstructible
and Assignable
requirements. And likewise, once the
MoveConstructible
and MoveAssignable
requirements (N1860) have made it
into the Working Draft, it seems undesirable to define the Swappable
requirement in terms of those requirements. Instead, it appears
preferable to have the Swappable
requirement defined exclusively in
terms of the existence of an appropriate swap function.
Section 20.1.4 [lib.swappable] of the current Working Draft (N2009) says:
The Swappable requirement is met by satisfying one or more of the following conditions:
- T is Swappable if T satisfies the CopyConstructible requirements (20.1.3) and the Assignable requirements (23.1);
- T is Swappable if a namespace scope function named swap exists in the same namespace as the definition of T, such that the expression swap(t,u) is valid and has the semantics described in Table 33.
I can think of three disadvantages of this definition:
If a client's type T satisfies the first condition (T is both CopyConstructible and Assignable), the client cannot stop T from satisfying the Swappable requirement without stopping T from satisfying the first condition.
A client might want to stop T from satisfying the Swappable requirement, because swapping by means of copy construction and assignment might throw an exception, and she might find a throwing swap unacceptable for her type. On the other hand, she might not feel the need to fully implement her own swap function for this type. In this case she would want to be able to simply prevent algorithms that would swap objects of type T from being used, e.g., by declaring a swap function for T, and leaving this function purposely undefined. This would trigger a link error, if an attempt would be made to use such an algorithm for this type. For most standard library implementations, this practice would indeed have the effect of stopping T from satisfying the Swappable requirement.
A client's type T that does not satisfy the first condition can not be made Swappable by providing a specialization of std::swap for T.
While I'm aware about the fact that people have mixed feelings about providing a specialization of std::swap, it is well-defined to do so. It sounds rather counter-intuitive to say that T is not Swappable, if it has a valid and semantically correct specialization of std::swap. Also in practice, providing such a specialization will have the same effect as satisfying the Swappable requirement.
For a client's type T that satisfies both conditions of the Swappable requirement, it is not specified which of the two conditions prevails. After reading section 20.1.4 [lib.swappable], one might wonder whether objects of T will be swapped by doing copy construction and assignments, or by calling the swap function of T.
I'm aware that the intention of the Draft is to prefer calling the swap function of T over doing copy construction and assignments. Still in my opinion, it would be better to make this clear in the wording of the definition of Swappable.
I would like to have the Swappable requirement defined in such a way that the following code fragment will correctly swap two objects of a type T, if and only if T is Swappable:
using std::swap; swap(t, u); // t and u are of type T.
This is also the way Scott Meyers recommends calling a swap function, in Effective C++, Third Edition, item 25.
Most aspects of this issue have been dealt with in a discussion on comp.std.c++ about the Swappable requirement, from 13 September to 4 October 2006, including valuable input by David Abrahams, Pete Becker, Greg Herlihy, Howard Hinnant and others.
[ San Francisco: ]
Recommend
NADResolved. Solved by N2774.
[ 2009-07 Frankfurt ]
Moved to Open. Waiting for non-concepts draft.
[ 2009-11-08 Howard adds: ]
This issue is very closely related to 742.
[ 2010-02-03 Sean Hunt adds: ]
While reading N3000, I independently came across Issue 594. Having seen that it's an issue under discussion, I think the proposed wording needs fixing to something more like "...function call swap(t,u) that includes std::swap in its overload set is valid...", because "...is valid within the namespace std..." does not allow other libraries to simply use the Swappable requirement by referring to the standard's definition, since they cannot actually perform any calls within std.
This wording I suggested would also make overloads visible in the same scope as the
using std::swap
valid for Swappable requirements; a more complex wording limiting the non-ADL overload set to std::swap might be required.
[ 2010 Pittsburgh: ]
Moved to NAD Editorial. Rationale added.
Rationale:
Solved by N3048.
Proposed resolution:
Change section 20.1.4 [lib.swappable] as follows:
The Swappable requirement is met by satisfying
one or more of the following conditions:the following condition:
T is Swappable if T satisfies the CopyConstructible requirements (20.1.3) and the Assignable requirements (23.1);T is Swappable if a namespace scope function named swap exists in the same namespace as the definition of T, such that the expression swap(t,u) is valid and has the semantics described in Table 33.T is Swappable if an unqualified function call swap(t,u) is valid within the namespace std, and has the semantics described in Table 33.