Doc. no.: | N4031
Date: | 2014-05-22
Project: | Programming Language C++, Library Working Group
Reply-to: | Zhihao Yuan <zy at miator dot net>

# make_array, revision 1

## Changes since N3824

- Editorial wording updates.
- Comments updates.

## Motivation

We have `make_tuple`, `make_pair`, but not `make_array`, while `std::array` creation can also benefit from this “semiofficial” tuple-like interface to deduce both element type and array bound.

## Scope

LWG 851 intended to provide a replacement syntax to

    array<T, N> a = { E1, E2, ... };

, so the following

    auto a = make_array(42u, 3.14);

is well-formed (with additional `static_cast`s applied inside) because

    array<double, 2> = { 42u, 3.14 };

is well-formed.

This paper intends to provide a set of `std::array` creation interfaces which are comprehensive from both `tuple`’s point of view and `array`’s point of view, so narrowing is just naturally banned. See more details driven by this direction in Design Decisions.

## Examples

    auto a1 = make_array(2, 3L);        // array<long, 2>
    auto ax = make_array(2, 3U);        // error: narrowing

    auto a2 = make_array<long>(2, 3U);      // explicit destination type
    auto ax = make_array<unsigned>(2, 3U);  // error: narrowing

    auto a3 = make_array("foo");        // array<char const*, 1>, decayed
    auto a4 = to_array("foo");          // array<char, 4>

## Design Decisions

- Provide both `make_tuple`-like, type-deduced interface and raw array style bound-deduced interface.

- Ban `reference_wrapper` in the `make_tuple`-like interface. `make_tuple` and `make_pair` have special handling of `reference_wrapper`, then user might expect that the expression

`make_array(ref(a), ref(b))`

> also results in a tuple-like object storing `T&`. However, `std::array` does not store “real” references, and any attempts to workaround this break the interfaces in different ways. Note that “doing nothing” is not an option since, for example, `common_type_t<reference_wrapper<int>, reference_wrapper<long>>` is `long`, not reference or `reference_wrapper`.

- A saperated interface to perform constructing from raw array instead of array-to-pointer conversion. `make_tuple` and `make_pair` unconditionally decay, but such a behavior, when being applied to `make_array`,

`make_array("raw array") // got array<char const*, 1>`

> is inexplicable. However, to keep the interfaces consistent, I decide to name a new utility differently instead of to ban this conversion.

## Wording

This wording is relative to N3936.

Add to 23.3.1/2 [sequences.general], `<array>` synopsis:

    namespace std {
      template <class T, size_t N > struct array;

> …

      template <class T, size_t N >
        void swap(array<T,N>& x, array<T,N>& y) noexcept(noexcept(x.swap(y)));

`template <class... Types>`
`constexpr see below make_array(Types&&...);`
`template <class D, class... Types>`
`constexpr see below make_array(Types&&...);`
`template <class T, size_t N>`
`constexpr see below to_array(T (&a)[N]);`

> …

    }

New section 23.3.2.9 [array.creation] (between [array.zero] and [array.tuple], which was 23.3.2.9):

> #### 23.3.2.9 Array creation functions [array.creation]

    template <class... Types>
      constexpr array<CT, sizeof...(Types)> make_array(Types&&...);

> Let Ui be `remove_reference_t<`Ti`>` for each Ti in `Types`.

> Remarks: This function shall not participate in overload resolution unless Ui is not `reference_wrapper<`Ti`>` for all i.

[Author’s note: We allow users to detect and handle this case. –end note]

> Returns: `array<CT, sizeof...(Types)>{ std::forward<Types>(t))... }`, where `CT` is `common_type_t<Types...>`.

> [Example:

        int i = 1; int& ri = i;
        make_array(i, ri, 42L)

> creates an `array` of type

        array<long, 3>

> –end example]

    template <class D, class... Types>
      constexpr array<D, sizeof...(Types)> make_array(Types&&...);

> Returns: `array<D, sizeof...(Types)>{ std::forward<Types>(t))... }`.

    template <class T, size_t N>
      constexpr array<V, N> to_array(T (&a)[N]);

> Returns: An `array<V, N>` such that each element is copy-initialized with the corresponding element of `a`, where `V` is `remove_cv_t<T>`.

[Author’s note: If `std::array` is extended to support multidimensional array (N3794), this function might get extended as well, but we don’t let users to roll their own. On the other hand, if users understand multidimensional `std::array` as `array` of `array`s, it might be more convenient and clear to write

    make_array(make_array(1, 2, 3), make_array(4, 5, 6)...)

instead of to adapt a raw array. –end note]

## Sample Implementation

A sample implementation is available at https://gist.github.com/lichray/6034753.

## Acknowledgments

Jonathan Wakely, who showed me how `index_sequence` helps initializing `std::array` from a raw array.

Daniel Krügler, who explained why an explicit destination type is essential.

Ville Voutilainen and other people who reviewed this paper.