Improving Pair and Tuple (Revision 2)

# Improving `pair` and `tuple`, revision 2

Addressed issues:

- LWG 2051.

- LWG 2397.

- LWG 2312 is partially addressed: The currently proposed wording still intends to make an implementation conforming that would accept a smaller number of elements values compared to the actual tuple-size (and to value-initialize the remaining ones), therefore the size-related requirements are currently not part of the SFINAE constraints. If LWG 2312 would be accepted the corresponding constraints would be similarly adjusted as described by the issue and the corresponding requirement could be removed.

## Revision History

Changes since N3739 (revision 1):

- Improved the current rationale (Thanks to Mike Spertus!)

- During the Rapperswil LEWG discussion a new vote lead to a revised result on the preferred representation form:

  > Do we prefer the `EXPLICIT(see below) constexpr tuple(UTypes&&...);` editorial representation?

  > SF-F-N-A-SA

  > 0-8-3-2-0

  Therefore this revision now uses the annotation `EXPLICIT` for the affected constructor pairs and defines the meaning of that in Clause 17.

Changes since N3680:

- During a straw-pool vote there was a small majority (4:3) in favour for keeping the two-signatures approach, so this presentation form was used in this revision.

- The original example has been improved.

- The missing application of the declaration pattern to the `allocator_arg_t` constructors has been fixed.

- Consequent usage of the more precise `is_convertible` trait instead of the somewhat vague is implicitly convertible description.

## Introduction

For many programmers it is a surprise to find out, that the following code is rejected by their compiler:

>     std::tuple<int, int> pixel_coordinates()
>     {
>       return {10, -15};  // Oops: Error
>     }

>     struct NonCopyable { NonCopyable(int); NonCopyable(const NonCopyable&) = delete; };

>     std::pair<NonCopyable, double> pmd{42, 3.14};  // Oops: Error

What is wrong with this? Why doesn't this just work?

This paper explains the reason for the current specification of `pair` and `tuple` and suggests changes to the working paper to fix these and some other bothersome constraints of these general type wrappers.

## Looking backwards

At the time when N3240 was proposed, several driving forces defined the constraints of resolving a bunch of library issues and NB comments.

One notable intention was to prevent that the type wrappers `tuple` and `pair` should allow implicit conversions for wrapped types that are not implicitly convertible, as expressed by LWG 1324 and DE 15.

Another relevant requirement was to keep backward-compatibility to C++03 in regard to null pointer literals expressed as integral null constants as described by LWG 811.

At that time there was a strong resistance to add further constructors especially to `std::pair`. At some point in time there did exist a very large number of such constructors due to allocator support. One important consequence of this pair simplification was the acceptance of N3059.

Thus with the previous acceptance of proposal N3240 the specification provides the following advantages for `pair` and `tuple`:

1. Heterogenous template constructors are constrained upon the criterion that the element-wise source types are implicitly convertible to the element-wise destination types.

   >     struct B { explicit B(bool); };

   >     std::tuple<B> tb = std::tuple<bool>(); // Error

2. The non-template constructor `tuple(const Types&...)` and the corresponding template-constructor are explicit. This prevents that a single-element tuple from being copy-initialized by an argument object and has only an explicit constructor for this construction.

   >     struct X { X(); explicit X(const X&); } x;

   >     std::tuple<X> tx = x; // Error

   >     struct E { explicit E(int); };

   >     std::tuple<E> te = 42; // Error

3. Non-template constructors accepting a sequence of elements, such as `explicit tuple(const Types&...)` and `pair(const T1& x, const T2& y)`, are still kept to support the special conversion scenario where a pointer(-to-member) element type is initialized with the null pointer constant `0` instead of `nullptr`.

   >     class C;

   >     std::tuple<int*> tpi(0); // OK
   >     std::tuple<int C::*> tpmi(0); // OK

## Discussion

We propose that `pair`/`tuple` obey the same initialization rules as their underlying element types. Unless we have such "perfect initialization", `pair` and `tuple` exhibit confusing and unintuitive behavior as illustrated by the examples below.

1. It means that `tuple` objects cannot be returned from a function as simple as this:

   >     std::tuple<int, int> foo_tuple()
   >     {
   >       return {1, -1};  // Error
   >     }

   >     std::pair<int, int> foo_pair()
   >     {
   >       return {1, -1};  // OK
   >     }

2. It means that `tuple` or `pair` objects cannot be constructed for element types that cannot be copied:

   >     struct D { D(int); D(const D&) = delete; };

   >     std::tuple<D> td(12); // Error

3. It even means that `tuple` or `pair` objects cannot be direct-constructed for element types via an explicit conversion:

   >     struct Y { explicit Y(int); };

   >     std::tuple<Y> ty(12); // Error

4. It has been observed by Johannes Schaub that there exists a defect with `tuple` in regard to the non-template constructor `explicit tuple(const Types&...)`: The current specification has the effect that the instantiation of `tuple<>` would be required to be ill-formed because it has two conflicting default constructors.

Starting with the last point: This is indeed a simple oversight that slipped in during the `tuple` standardization. The TR1 document did have the following specification:

>     template <class T1 = unspecified ,
>               class T2 = unspecified ,
>               ...,
>               class TM = unspecified >
>     class tuple
>     {
>     public:
>       tuple();
>       explicit tuple(P1, P2, ..., PN); // iff N > 0
>       […]
>     };

When the variadic form of tuples was proposed via N2151 and its successors, the highlighted size constraint inadvertently got lost.

The other three problems are all caused by (A) constructors that are always explicit and (B) by constrained constructor templates that impose implicit convertible constraints on the element types.

So, notwithstanding the good motivation behind the current specification of `pair` and `tuple`, it turns out to have some unfortunate consequences.

This proposal is intending to solve all these problems by a simple procedure that still ensures that all positive aspects of the current specification are conserved.

## "Perfect initialization"

Before explaining the general outline of this proposal it is more helpful to start with a simple, but useful programming idiom.

Consider the following class template `A` that is intended to be used as a wrapper for some other type `T`:

>     #include <type_traits>
>     #include <utility>

>     template<class T>
>     struct A {
>       template<class U,
>         typename std::enable_if<
>           std::is_constructible<T, U>::value &&
>           std::is_convertible<U, T>::value
>         , bool>::type = false
>       >
>       A(U&& u) : t(std::forward<U>(u)) {}

>      template<class U,
>         typename std::enable_if<
>           std::is_constructible<T, U>::value &&
>           !std::is_convertible<U, T>::value
>         , bool>::type = false
>       >
>       explicit A(U&& u) : t(std::forward<U>(u)) {}

>       T t;
>     };

The shown constructors both use perfect forwarding and they have essentially the same signatures except for one being explicit, the other one not. Furthermore, they are mutually exclusively constrained. In other words: This combination behaves for any destination type `T` and any argument type `U` like a single constructor that is either explicit or non-explicit (or no constructor at all). Attempts to construct a `A<T>` from some value of type `U` will reflect the allowed initialization forms of the wrapped type `T`:

>     struct Im{ Im(int){} };
>     struct Ex{ explicit Ex(int){} };

>     A<Im> ai1(1); // OK
>     A<Im> ai2{2}; // OK

>     A<Im> ai3 = 3;   // OK
>     A<Im> ai4 = {4}; // OK

>     A<Ex> ae1(1); // OK
>     A<Ex> ae2{2}; // OK

>     A<Ex> ae3 = 3;   // Error
>     A<Ex> ae4 = {4}; // Error

This technique can easily be extended to the variadic template case, and when doing so can be considered as a key to solving the problems of `tuple` and `pair`.

It should be noted here, that for the general case the `std::is_constructible<T, U>::value` requirement for the non-explicit constructor which is constrained on `std::is_convertible<U, T>::value` is not redundant, because it is possible to create types that can be copy-initialized but not direct-initialized:

>     struct Odd {
>       explicit Odd(int) = delete;
>       Odd(long){}
>     };

>     Odd o2 = 1; // OK
>     Odd o1(1);  // Error

Technically it would be possible to apply the same technique of creating element-dependent explicit or non-explicit default constructors. This application was shortly considered during the write-up of this proposal, but rejected because for the current C++ rules there is no longer any observable difference for an `explicit` default constructor that cannot be invoked with more than zero arguments and one that is not `explicit`.

The technique cannot be applied to copy/move operators in the same way as for the other constructors (because these special member functions cannot be templates) and given the very rare request for such a support the idea was no further investigated by the author. A second argument against providing this support is based on the consistency with the core language rules that the `explicit`-character of these constructors is not conserved for the implicitly declared versions in classes that contain corresponding sub-objects with such explicit constructors.

## Outline

As shown above, the current over-constraining restrictions of the `pair` and `tuple` constructors are due to unconditional usage of explicit and implicitly convertible requirements.

The general approach of this proposal is to require "perfect initialization" semantics for `pair` and `tuple` constructors extended to the variadic case. Albeit this seemingly doubles the number of constructor declarations in the draft, it does not change the effective number of these for a particular combination of element type and source type of some initialization due to their mutual exclusion property.

In theory the same technique could be applied to the `piecewise_construct_t` of `pair`. This proposal does not propose this, because this constructor is specifically asked for by the corresponding tag and there are no further constraint except the `is_constructible` requirements.

In addition, this proposal fixes the specification problem of `tuple<>`'s default constructors.

The wording is intentionally chosen, so that an implementation is not required (but allowed) to use the "perfect initialization" idiom.

This is done by taking advantage of the already existing nomenclature "This function does not participate in overload resolution unless […]". Its worth emphasizing that even though this phrase is usually used to describe constrained templates in the Library specification, the actual wording of this doesn't necessarily imply to "sfinae out" template functions. Many library implementations solve this problem by providing a specialization for the empty `tuple` case that does not provide the additional default constructor, for example. This is also a valid way to ensure that functions don't participate in overload resolution.

## Why not explicit for single argument constructors only?

In C++03 `explicit` constructors had no behavioural difference, unless they had been single-argument constructors, so one might suggest to restrict adding the `explicit` keyword to constructors that take exactly one argument.

I think this is idea is flawed (unless I'm using specifically tagged constructors like the piecewise-one of `pair`). Consider the following example:

>     #include <tuple>
>     #include <chrono>
>     #include <iostream>

>     using hms_t = std::tuple<std::chrono::hours, std::chrono::minutes, std::chrono::seconds>;

>     void launch_rocket_at(std::chrono::seconds s)
>     {
>       std::cout << "launching rocket in " << s.count() << " seconds!\n";
>     }

>     void launch_rocket_at(hms_t times)
>     {
>       using namespace std;
>       launch_rocket_at(get<0>(times) + get<1>(times) + get<2>(times));
>     }

>     int main()
>     {
>       using namespace std;
>       launch_rocket_at(make_tuple(1, 2, 3)); // #1: very scary
>       launch_rocket_at({1, 2, 3});           // #2: even scarier
>       using namespace std::chrono;
>       launch_rocket_at(make_tuple(hours(1), minutes(2), seconds(3))); // #3: Perfectly clear!
>       launch_rocket_at({hours(1), minutes(2), seconds(3)});           // #4: Also clear!
>       launch_rocket_at(hms_t{1, 2, 3});                               // #5: And this, too
>     }

which should output:

>     launching rocket in 3723 seconds!
>     launching rocket in 3723 seconds!
>     launching rocket in 3723 seconds!

If the former two calls to function `launch_rocket_at` where possible, this would directly subvert the intended explicitness of the `std::duration` constructor and would make using the time-utility types much more unsafe. Why? Consider the following scenario:

If the client believed that the order of the units was seconds, minutes, hours, and input 3, 2, 1, — intending 3 seconds, 2 minutes, and 1 hour — the rocket would launch in 10,921 seconds instead of the intended 3,723 seconds. This mistake can indeed easily happen, if you look again at the lines marked with #1 and #2.

Due to our intentionally conserved constraints to be explicit here we catch that mistake at compile-time, instead of having to shoot the rocket down...

## Editorial Representation

During the write-up of this proposal I had the idea of replacing the prototype declaration pairs by a single one expressed by some pseudo-macro that looks like a single declaration. For example

>     template <class... UTypes>
>     constexpr tuple(UTypes&&...);
>     template <class... UTypes>
>     explicit constexpr tuple(UTypes&&...);

could instead be declared as follows:

>     template <class... UTypes>
>     EXPLICIT constexpr tuple(UTypes&&...);

This form of representation still means that `EXPLICIT` needs to be defined somewhere and somehow, but only once.

There was a strong preference during the Rapperswil 2014 LEWG discussion to use the "macro" instead of the individual declarations.

This paper does not use a previously suggested form of `EXPLICIT(see below)` instead of `EXPLICIT`, because there is nothing specific to explain below again (The different SFINAE conditions are not relevant at that point, because they appear as usual with the normal, detailed prototype specifications).

In any way, the final editorial decision is being handed over to the project editor.

## Proposed resolution

The proposed wording changes refer to N3936.

1. Insert the following new sub-clause immediately following 17.5.2.3 [objects.within.classes] as a further children of 17.5.2 [conventions]:

   `EXPLICIT` constructors [explicit.within.classes]

   > -?- For the sake of exposition, the library clauses sometimes annotate constructors with `EXPLICIT`. For every constructor declaration that contains `EXPLICIT`, the meaning is equivalent to two consecutive declarations of exactly the same members, except that one of these two members has the `EXPLICIT` removed and the other one is declared with a function-specifier `explicit` instead of `EXPLICIT`.

2. Change 20.3.2 [pairs.pair], class template `pair` synopsis, as indicated:

   >     namespace std {
   >       template <class T1, class T2>
   >       struct pair {
   >         typedef T1 first_type;
   >         typedef T2 second_type;

   >         T1 first;
   >         T2 second;
   >         pair(const pair&) = default;
   >         pair(pair&&) = default;
   >         constexpr pair();
   >         EXPLICIT constexpr pair(const T1& x, const T2& y);
   >         template<class U, class V> EXPLICIT constexpr pair(U&& x, V&& y);
   >         template<class U, class V> EXPLICIT constexpr pair(const pair<U, V>& p);
   >         template<class U, class V> EXPLICIT constexpr pair(pair<U, V>&& p);
   >         template <class... Args1, class... Args2>
   >         pair(piecewise_construct_t,
   >           tuple<Args1...> first_args, tuple<Args2...> second_args);

   >         pair& operator=(const pair& p);
   >         template<class U, class V> pair& operator=(const pair<U, V>& p);
   >         pair& operator=(pair&& p) noexcept(see below);
   >         template<class U, class V> pair& operator=(pair<U, V>&& p);

   >         void swap(pair& p) noexcept(see below);
   >       };
   >     }

3. Change 20.3.2 [pairs.pair] around p5 as indicated:

   >     EXPLICIT constexpr pair(const T1& x, const T2& y);

   > > -5- Requires: `is_copy_constructible<first_type>::value` is `true` and `is_copy_constructible<second_type>::value` is `true`.

   > > -6- Effects: The constructors initializes `first` with `x` and `second` with `y`.

   > > -?- Remarks: The non-explicit constructor shall not participate in overload resolution unless

   > > - `is_copy_constructible<first_type>::value` is `true` and `is_copy_constructible<second_type>::value` is `true`, and

   > > - `is_convertible<const first_type&, first_type>::value` is `true` and `is_convertible<const second_type&, second_type>::value` is `true`

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `is_copy_constructible<first_type>::value` is `true` and `is_copy_constructible<second_type>::value` is `true`, and

   > > - `is_convertible<const first_type&, first_type>::value` is `false` or `is_convertible<const second_type&, second_type>::value` is `false`

4. Change 20.3.2 [pairs.pair] around p7 as indicated:

   >     template<class U, class V> EXPLICIT constexpr pair(U&& x, V&& y);

   > > -7- Requires: `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`.

   > > -8- Effects: The constructors initializes `first` with `std::forward<U>(x)` and `second` with `std::forward<V>(y)`.

   > > -9- Remarks: If `U` is not implicitly convertible to `first_type` or `V` is not implicitly convertible to `second_type` this constructor shall not participate in overload resolution. The non-explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`, and

   > > - `is_convertible<U&&, first_type>::value` is `true` and `is_convertible<V&&, second_type>::value` is `true`

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`, and

   > > - `is_convertible<U&&, first_type>::value` is `false` or `is_convertible<V&&, second_type>::value` is `false`

5. Change 20.3.2 [pairs.pair] around p10 as indicated:

   >     template<class U, class V> EXPLICIT constexpr pair(const pair<U, V>& p);

   > > -10- Requires: `is_constructible<first_type, const U&>::value` is `true` and `is_constructible<second_type, const V&>::value` is `true`.

   > > -11- Effects: The constructors initializeInitializes members from the corresponding members of the argument.

   > > -12- Remarks: This constructor shall not participate in overload resolution unless `const U&` is implicitly convertible to `first_type` and `const V&` is implicitly convertible to `second_type`. The non-explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, const U&>::value` is `true` and `is_constructible<second_type, const V&>::value` is `true`, and

   > > - `is_convertible<const U&, first_type>::value` is `true` and `is_convertible<const V&, second_type>::value` is `true`

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, const U&>::value` is `true` and `is_constructible<second_type, const V&>::value` is `true`, and

   > > - `is_convertible<const U&, first_type>::value` is `false` or `is_convertible<const V&, second_type>::value` is `false`

6. Change 20.3.2 [pairs.pair] around p13 as indicated:

   >     template<class U, class V> EXPLICIT constexpr pair(pair<U, V>&& p);

   > > -13- Requires: `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`.

   > > -14- Effects: The constructors initializes `first` with `std::forward<U>(p.first)` and `second` with `std::forward<V>(p.second)`.

   > > -15- Remarks: This constructor shall not participate in overload resolution unless `U` is implicitly convertible to `first_type` and `V` is implicitly convertible to `second_type`. The non-explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`, and

   > > - `is_convertible<U&&, first_type>::value` is `true` and `is_convertible<V&&, second_type>::value` is `true`

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `is_constructible<first_type, U&&>::value` is `true` and `is_constructible<second_type, V&&>::value` is `true`, and

   > > - `is_convertible<U&&, first_type>::value` is `false` or `is_convertible<V&&, second_type>::value` is `false`

7. Change 20.4.2 [tuple.tuple], class template `tuple` synopsis, as indicated. The intent is to declare the set of "conditionally explicit" constructors and to fix the multiple default constructor problem for empty tuples.

   >     namespace std {
   >       template <class... Types>
   >       class tuple {
   >       public:
   >         // 20.4.2.1, tuple construction
   >         constexpr tuple();
   >         EXPLICITexplicit constexpr tuple(const Types&...); // only if sizeof...(Types) >= 1
   >         template <class... UTypes>
   >           EXPLICITexplicit constexpr tuple(UTypes&&...);   // only if sizeof...(Types) >= 1

   >         tuple(const tuple&) = default;
   >         tuple(tuple&&) = default;

   >         template <class... UTypes>
   >           EXPLICIT constexpr tuple(const tuple<UTypes...>&);
   >         template <class... UTypes>
   >           EXPLICIT constexpr tuple(tuple<UTypes...>&&);

   >         template <class U1, class U2>
   >           EXPLICIT constexpr tuple(const pair<U1, U2>&);          // only if sizeof...(Types) == 2
   >         template <class U1, class U2>
   >           EXPLICIT constexpr tuple(pair<U1, U2>&&);               // only if sizeof...(Types) == 2

   >         // allocator-extended constructors
   >         template <class Alloc>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a);
   >         template <class Alloc>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
   >         template <class Alloc, class... UTypes>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
   >         template <class Alloc>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple&);
   >         template <class Alloc>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple&&);
   >         template <class Alloc, class... UTypes>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
   >         template <class Alloc, class... UTypes>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
   >         template <class Alloc, class U1, class U2>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
   >         template <class Alloc, class U1, class U2>
   >           EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);

   >         [..]
   >       };
   >     }

8. Change 20.4.2.1 [tuple.cnstr] around p6 as indicated:

   >     EXPLICITexplicit constexpr tuple(const Types&...);

   > > -6- Requires: `is_copy_constructible<Ti>::value` is true for all i.

   > > -7- Effects: The constructors initializeInitializes each element with the value of the corresponding parameter.

   > > -?- Remarks: The non-explicit constructor shall not participate in overload resolution unless

   > > - `sizeof...(Types) >= 1`,

   > > - `is_copy_constructible<Ti>::value` is `true` for all i, and

   > > - `is_convertible<const Ti&, Ti>::value` is `true` for all i

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `sizeof...(Types) >= 1`,

   > > - `is_copy_constructible<Ti>::value` is `true` for all i, and

   > > - `is_convertible<const Ti&, Ti>::value` is `false` for at least one i

9. Change 20.4.2.1 [tuple.cnstr] around p8 as indicated:

   >     template <class... UTypes>
   >       EXPLICITexplicit constexpr tuple(UTypes&&... u);

   > > -8- Requires: `sizeof...(Types) == sizeof...(UTypes)`. `is_constructible<Ti, Ui&&>::value` is true for all i.

   > > -9- Effects: The constructors initializeInitializes the elements in the tuple with the corresponding value in `std::forward<UTypes>(u)`.

   > > -10- Remarks: This constructor shall not participate in overload resolution unless each type in `UTypes` is implicitly convertible to its corresponding type in `Types`. The non-explicit constructor shall not participate in overload resolution unless

   > > - `sizeof...(Types) >= 1`,

   > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

   > > - `is_convertible<Ui&&, Ti>::value` is `true` for all i

   > > The explicit constructor shall not participate in overload resolution unless

   > > - `sizeof...(Types) >= 1`,

   > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

   > > - `is_convertible<Ui&&, Ti>::value` is `false` for at least one i

10. Change 20.4.2.1 [tuple.cnstr] around p15 as indicated:

    >     template <class... UTypes> EXPLICIT constexpr tuple(const tuple<UTypes...>& u);

    > > -15- Requires: `sizeof...(Types) == sizeof...(UTypes)`. `is_constructible<Ti, const Ui&>::value` is true for all i.

    > > -16- Effects: The constructors initializeConstructs each element of `*this` with the corresponding element of `u`.

    > > -17- Remarks: This constructor shall not participate in overload resolution unless `const Ui&` is implicitly convertible to `Ti` for all i. The non-explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, const Ui&>::value` is `true` for all i, and

    > > - `is_convertible<const Ui&, Ti>::value` is `true` for all i

    > > The explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, const Ui&>::value` is `true` for all i, and

    > > - `is_convertible<const Ui&, Ti>::value` is `false` for at least one i

11. Change 20.4.2.1 [tuple.cnstr] around p18 as indicated:

    >     template <class... UTypes> EXPLICIT constexpr tuple(tuple<UTypes...>&& u);

    > > -18- Requires: `sizeof...(Types) == sizeof...(UTypes)`. `is_constructible<Ti, Ui&&>::value` is true for all i.

    > > -19- Effects: For all i, the constructors initializes the ith element of `*this` with `std::forward<Ui>(get<i>(u))`.

    > > -20- Remarks: This constructor shall not participate in overload resolution unless each type in `UTypes` is implicitly convertible to its corresponding type in `Types`. The non-explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

    > > - `is_convertible<Ui&&, Ti>::value` is `true` for all i

    > > The explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

    > > - `is_convertible<Ui&&, Ti>::value` is `false` for at least one i

12. Change 20.4.2.1 [tuple.cnstr] around p21 as indicated:

    >     template <class U1, class U2> EXPLICIT constexpr tuple(const pair<U1, U2>& u);

    > > -21- Requires: `sizeof...(Types) == 2`. `is_constructible<T0, const U1&>::value` is true for the first type `T0` in `Types` and `is_constructible<T1, const U2&>::value` is true for the second type `T1` in `Types`.

    > > -22- Effects: The constructors initializeConstructs the first element with `u.first` and the second element with `u.second`.

    > > -23- Remarks: This constructor shall not participate in overload resolution unless `const U1&` is implicitly convertible to `T0` and `const U2&` is implicitly convertible to `T1`. The non-explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, const Ui&>::value` is `true` for all i, and

    > > - `is_convertible<const Ui&, Ti>::value` is `true` for all i

    > > The explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, const Ui&>::value` is `true` for all i, and

    > > - `is_convertible<const Ui&, Ti>::value` is `false` for at least one i

13. Change 20.4.2.1 [tuple.cnstr] around p24 as indicated:

    >     template <class U1, class U2> EXPLICIT constexpr tuple(pair<U1, U2>&& u);

    > > -24- Requires: `sizeof...(Types) == 2`. `is_constructible<T0, U1&&>::value` is true for the first type `T0` in `Types` and `is_constructible<T1, U2&&>::value` is true for the second type `T1` in `Types`.

    > > -25- Effects: The constructors iInitializes the first element with `std::forward<U1>(u.first)` and the second element with `std::forward<U2>(u.second)`.

    > > -26- Remarks: This constructor shall not participate in overload resolution unless `U1` is implicitly convertible to `T0` and `U2` is implicitly convertible to `T1`. The non-explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

    > > - `is_convertible<Ui&&, Ti>::value` is `true` for all i

    > > The explicit constructor shall not participate in overload resolution unless

    > > - `is_constructible<Ti, Ui&&>::value` is `true` for all i, and

    > > - `is_convertible<Ui&&, Ti>::value` is `false` for at least one i

14. Change 20.4.2.1 [tuple.cnstr] around p27 as indicated:

    >     template <class Alloc>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a);
    >     template <class Alloc>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, const Types&...);
    >     template <class Alloc, class... UTypes>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, UTypes&&...);
    >     template <class Alloc>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple&);
    >     template <class Alloc>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple&&);
    >     template <class Alloc, class... UTypes>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&);
    >     template <class Alloc, class... UTypes>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&&);
    >     template <class Alloc, class U1, class U2>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&);
    >     template <class Alloc, class U1, class U2>
    >       EXPLICIT tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&);

    > > -27- Requires: `Alloc` shall meet the requirements for an `Allocator` (17.6.3.5).

    > > -28- Effects: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction (20.8.7.2).

## Implementation Hint

The following example presents how to constrain even non-template functions such as the constructors that directly take the element types.

>     template<class T1, class T2>
>     struct pair {

>       […]

>       template<class U1 = T1, class U2 = T2,
>         typename enable_if<
>           is_copy_constructible<U1>::value && is_copy_constructible<U2>::value &&
>           is_convertible<const U1&, U1>::value && is_convertible<const U2&, U2>::value
>         , bool>::type = false
>       >
>       constexpr pair(const T1&, const T2&);

>       template<class U1 = T1, class U2 = T2,
>         typename enable_if<
>           is_copy_constructible<U1>::value && is_copy_constructible<U2>::value &&
>           !(is_convertible<const U1&, U1>::value && is_convertible<const U2&, U2>::value)
>         , bool>::type = false
>       >
>       explicit constexpr pair(const T1&, const T2&);
>     };

## Acknowledgements

I would like to thank Howard Hinnant for his very helpful discussions and comments during reviews of this paper and for his motivating example. Thanks also to Jonathan Wakely for his review that improved this proposal to a large extend. Thanks as well go to Mike Spertus for helping to improve the rationale.