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

# make_array, revision 2

## Changes since N4031

- `make_array<D>` renamed to `array_of<D>`.
- Fixed cv-`reference_wrapper<T>` detection.

## 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 = array_of<long>(2, 3U);      // explicit destination type
    auto ax = array_of<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 array_of(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 `decay_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)> array_of(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]

## Alternative Design

The past two revisions of this paper adds 2 names (`make_array`, `to_array`) rather than 3 (with the standalone `array_of`). If you prefer keeping the number of symbols minimal, or believe that the type&bound-deduced interface and the bound-deduced-only interface should be named the same, here is an alternative wording for such a design.

## 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.

Stephan T. Lavavej, who pointed out the ambiguity issue of the two `make_array` overloads, and came with with the naming ”`*_of`”.