This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
Section: 23.3.3 [array] Status: NAD Submitter: Benjamin Kosnik Opened: 2008-06-05 Last modified: 2017-06-06
Priority: Not Prioritized
View all other issues in [array].
View all issues with NAD status.
Discussion:
This is an issue that came up on the libstdc++ list, where a
discrepancy between "C" arrays and C++0x's std::array
was pointed
out.
In "C," this array usage is possible:
int ar[] = {1, 4, 6};
But for C++,
std::array<int> a = { 1, 4, 6 }; // error
Instead, the second parameter of the array
template must be
explicit, like so:
std::array<int, 3> a = { 1, 4, 6 };
Doug Gregor proposes the following solution, that assumes generalized initializer lists.
template<typename T, typename... Args> inline array<T, sizeof...(Args)> make_array(Args&&... args) { return { std::forward<Args>(args)... }; }
Then, the way to build an array
from a list of unknown size is:
auto a = make_array<T>(1, 4, 6);
[ San Francisco: ]
Benjamin: Move to Ready?
Bjarne: I'm not convinced this is useful enough to add, so I'd like us to have time to reflect on it.
Alisdair: the constraints are wrong, they should be
template<ValueType T, ValueType... Args> requires Convertible<Args, T>... array<T, sizeof...(Args)> make_array(Args&&... args);Alidair: this would be useful if we had a constexpr version.
Bjarne: this is probably useful for arrays with a small number of elements, but it's not clearly useful otherwise.
Consensus is to move to Open.
[ 2009-06-07 Daniel adds: ]
I suggest a fix and a simplification of the current proposal: Recent prototyping by Howard showed, that a fix is required because narrowing conversion 9.4.5 [dcl.init.list]/6 b.3 would severely limit the possible distribution of argument types, e.g. the expression
make_array<double>(1, 2.0)
is ill-formed, because the narrowing happens inside the function body where no constant expressions exist anymore. Furthermore given e.g.int f(); double g();we probably want to support
make_array<double>(f(), g());as well. To make this feasible, the currently suggested expansion
{ std::forward<Args>(args)... }needs to be replaced by
{ static_cast<T>(std::forward<Args>(args))... }which is safe, because we already ensure convertibility via the element-wise
Convertible<Args, T>
requirement. Some other fixes are necessary: TheValueType
requirement for the function parameters is invalid, because all lvalue arguments will deduce to an lvalue-reference, thereby no longer satisfying this requirement.The suggested simplification is to provide a default-computed effective type for the result array based on common_type and decay, in unconstrained form:
template<typename... Args> array<typename decay<typename common_type<Args...>::type>::type, sizeof...(Args)> make_array(Args&&... args);The approach used below is similar to that of
make_pair
andmake_tuple
using a symbolC
to represent the decayed common type [Note: Special handling ofreference_wrapper
types is intentionally not provided, because our target has so satisfyValueType
, thus under the revised proposal only an all-reference_wrapper
-arguments would be well-formed and an array ofreference_wrapper
will be constructed]. I do currently not suggest to add new concepts reflectingdecay
andcommon_type
, but an implementor will need something like this to succeed. Note that we use a similar fuzziness formake_pair
andmake_tuple
currently. This fuzziness is not related to the currently missingConstructible<Vi, Ti&&>
requirement for those functions. The following proposal fixes that miss formake_array
. If the correspondingC
type deduction is explicitly wanted for standardization, here the implementationauto concept DC<typename... T> { typename type = typename decay<typename common_type<T...>::type>::type; }where
C
is identical toDC<Args...>::type
in the proposed resolution below.I intentionally added no further type relation between type and the concept template parameters, but instead added this requirement below to make the specification as transparent as possible. As written this concept is satisfied, if the corresponding associated type exists.
Suggested Resolution:
Add to the array synopsis in 23.3 [sequences]:
template<ReferentType... Args> requires ValueType<C> && IdentityOf<Args> && Constructible<C, Args&&>... array<C, sizeof...(Args)> make_array(Args&&... args);Append after 23.3.3.7 [array.tuple] Tuple interface to class template array the following new section:
23.4.1.7 Array creation functions [array.creation]
template<ReferentType... Args> requires ValueType<C> && IdentityOf<Args> && Constructible<C, Args&&>... array<C, sizeof...(Args)> make_array(Args&&... args);Let
C
bedecay<common_type<Args...>::type>::type
.Returns: an
array<C, sizeof...(Args)>
initialized with{ static_cast<C>(std::forward<Args>(args))... }
.
[ 2009-07 Frankfurt: ]
The proposed resolution uses concepts.
Daniel to rewrite the proposed resolution.
Leave Open.
[ 2009-07-25 Daniel provides rewritten proposed resolution. ]
[ 2009-10 Santa Cruz: ]
Argument for NAD future: everything about this could be added on. This does not require changes to the existing text.
[2015-11-29, Alisdair comments]
N4391 was adopted for Fundamentals 2 at the Lenexa meeting.
[2017-02 in Kona, LEWG recommends NAD]
[2017-06-02 Issues Telecon]
It seems as if deduction guides can solve most of the problem. In addition to that, make_array is available in Library Fundamentals TS v2. If it's desired to be able to specify the type but not the extent, make_array can do that, and if make_array isn't acceptable for that, we are talking about a language extension in deduction guides, which needs a proposal paper.
Resolve as NAD
Proposed resolution:
Add to the array synopsis in 23.3 [sequences]:
template<class... Args> array<CT, sizeof...(Args)> make_array(Args&&... args);
Append after 23.3.3.7 [array.tuple] "Tuple interface to class template array" the following new section:
XX.X.X.X Array creation functions [array.creation]
template<class... Args> array<CT, sizeof...(Args)> make_array(Args&&... args)Let CT be
decay<common_type<Args...>::type>::type
.Returns: An
array<CT, sizeof...(Args)>
initialized with{ static_cast<CT>(std::forward<Args>(args))... }
.[Example:
int i = 0; int& ri = i; make_array(42u, i, 2.78, ri);returns an array of type
array<double, 4>—end example]