问题
C++20 adopted p0960 - allowing initialization of aggregates from a parenthesized list of values.
The exact wording ([dcl.init] 17.6.2.2) says:
[...] if no constructor is viable, the destination type is an aggregate class, and the initializer is a parenthesized expression-list, the object is initialized as follows.
Let e1 , …, en be the elements of the aggregate ([dcl.init.aggr]).
Let x1, …, xk be the elements of the expression-list.
If k is greater than n, the program is ill-formed.
The element ei is copy-initialized with xi for 1 ≤ i ≤ k . The remaining elements are initialized with their default member initializers [...]
This doesn't allow initialization of inner array with parenthesized list of values:
struct Foo {
int i, j;
};
struct Moo {
int arr[2];
};
int main() {
// before C++20:
Foo foo1{1, 2};
// with C++20:
Foo foo2(1, 2); // p0960! we are good
// before C++20:
Moo moo1{1, 2};
// C++20 - oops p0960 doesn't help here:
Moo moo2(1, 2); // error: too many initializers
// before C++20:
std::array<int, 2> arr1{1, 2}; // OK
std::array<int, 2> arr2({1, 2}); // OK
std::array<int, 2> arr3{{1, 2}}; // OK
// C++20 - oops p0960 doesn't help here:
std::array<int, 2> arr4(1, 2); // error: too many initializers
}
The fact that std::array
cannot be initialized with rounded brackets prevents it from participating in a generic code that creates an object of unknown type T
from a list of values (e.g. an algorithm that uses make_shared
, make_unique
, make_from_tuple
etc.).
Why p0960 didn't take a more simple approach making ()-initialization more like {}?
For example, something like:
if no constructor is viable, the destination type is an aggregate class, and the initializer is a parenthesized expression-list, the object would be initialized as if the values were sent with brace-initialization.
回答1:
p0960 changed between r1 and r2:
r2: This revision changes the mental model from the original “literal rewrite to a braced list” to “as if a synthesized, explicit constructor with appropriate mem-initializers was called”1. This has the effect of allowing narrowing conversions in the parenthesized list, even when narrowing conversions would be forbidden in the corresponding braced list syntax. It also clarifies the non-extension of temporary lifetimes of temporaries bound to references, the absence of brace elision, and the absence of a well-defined order of evaluation of the arguments.
The reason why this change was made can be found in the changed design principles for p0960:
r1: Parenthesized initialization and braced-initialization should be as similar as possible.
r2: Parenthesized initialization and braced-initialization should be as similar as possible, but as distinct as necessary to conform with the existing mental models of braced lists and parenthesized lists. (emphasis mine)
"Why p0960 didn't take a more simple approach making ()-initialization more like {}?":
When the decision to go for conformance with the existing mental models 1 had been taken, not allowing brace elision seems like the only approach.
来源:https://stackoverflow.com/questions/62041402/c20-initializing-aggregates-from-a-parenthesized-list-of-values-not-supportin