In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
How to understand C++ list initialization syntax, I believe that many inexperienced people do not know what to do, so this paper summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.
A friend found a strange problem when using std::array: when the element type is a compound type, the compilation will not pass.
Struct S {int x; int y;}; int main () {int A1 [3] {1,2,3}; / simple type, native array std::array a2 {1,2,3}; / / simple type, std::array SA3 [3] {{1,2}, {3,4}, {5,6}} / / compound type, native array std::array a4 {{1, 2}, {3, 4}, {5, 6}}; / / compound type, std::array, compilation failed! Return 0;}
The behavior of std::array and native arrays is almost the same, but why is the initialization syntax different when element types are different? More oddly, if you add an extra layer of parentheses, or remove the inner parentheses, you can make the code compile:
Std::array A1 {{1,2}, {3,4}, {5,6}}; / / initialization of the native array, compilation failed! Std::array a2 {1, 2}, {3, 4}, {5, 6}}; / / std::array A3 {1, 2, 3, 4, 5, 6} is compiled successfully with an extra layer of parentheses; / / the inner layer is compiled without parentheses
This article will introduce the principle of this problem and the correct solution.
Aggregation initialization
Let's start with the internal implementation of std::array. In order for std::array to behave like a native array, the std::array in C++ is very different from other STL containers-std::array does not define any constructors, and all internal data members are public. This makes std::array an aggregate.
The definition of aggregation is slightly different in each C++ version. Here is a brief summary of the definition in aggregate 17: an class or struct type is called an aggregation [1] when it meets the following conditions:
No private or protected data members
There are no user-supplied constructors (except for those explicitly declared with = default or = delete)
There is no virtual, private, or protected base class
There is no virtual function
Intuitively, aggregations often correspond to struct types that contain only data, often referred to as POD types. In addition, native array types are all aggregates.
Aggregation can be initialized with a list of curly braces. In general, the elements in curly braces correspond to the aggregated elements one by one, and the nesting of curly braces is consistent with the nesting of aggregation types. In C language, we often see such struct initialization statements.
After understanding the above principle, it is easy to understand why the initialization of std::array is successful with an extra layer of curly braces-because the only element inside the std::array is a native array, there are two layers of nesting. A custom MyArray type is shown below. Its data structure is almost the same as that of std::array, and its initialization method is similar:
Struct S {int x; int y;}; templatestruct MyArray {T data [N];}; int main () {MyArray A1 {{1,2,3}}; / / two braces MyArray a2 {1,2}, {3,4}, {5,6}}; / / three braces return 0;}
In the above example, the outermost curly braces of the initialization list correspond to MyArray, followed by the data member data, followed by elements in data. The nesting of curly braces is exactly the same as nesting between types. This is std::array 's strict and complete initialization curly braces.
But why is it okay to leave out a layer of curly braces when the std::array element type is a simple type? This involves another feature of aggregation initialization: curly braces omission.
Curly braces omitted (brace elision)
C++ allows you to omit one or more layers of curly braces when the internal members of the aggregation are still aggregates. When curly braces are omitted, the compiler populates them in turn according to the number of elements contained in the inner aggregation.
The following code, though unusual, is legal. Although the two-dimensional array initialization uses only one layer of curly braces, because the curly braces are omitted, the compiler fills the inner array with all the elements in turn-- the previous one fills up and then the next one.
Int a [3] [2] {1,2,3,4,5,6}; / equivalent to {{1,2}, {3,4}, {5,6}}
Once you know the principle of omitting curly braces, you know the principle that std::array initialization uses only one layer of curly braces: because the internal member array of std::array is an aggregation, when the compiler sees a list like {1-line-2-line-3}, it will fill the elements of the internal array with the elements in the braces one by one. Even if there are two arrays inside the std::array, it will fill in the last array one in turn.
This also explains why complex types can be compiled successfully without inner curly braces:
Std::array A3 {1, 2, 3, 4, 5, 6}; / / compiled successfully without parentheses in the inner layer
Because S is also an aggregation type, two layers of braces are omitted here. The compilation time fills the elements in the following order: array element 0, element 0, element 1, element 1, element
Although curly braces can be omitted, once the user explicitly writes curly braces, it must correspond strictly to the number of elements in this layer. Therefore, the following words will report an error:
Std::array A1 {{1,2}, {3,4}, {5,6}}; / / compilation failed!
The compiler assumes that {1pr 2} corresponds to the internal array of std::array, and then {3pr 4} corresponds to the next internal member of std::array. However, std::array has only one data member, so it reports an error: too many initializers for 'std::array'
It is important to note that the curly braces omission is only valid for aggregation types. If S had a custom constructor, it would not work to save the curly braces:
/ / aggregate struct S1 {S1 () = default; int x; int y;}; std::array A1 {1, 2, 3, 4, 5, 6}; / / OK// aggregate struct S2 {S2 () = delete; int x; int y;}; std::array a2 {1, 2, 3, 4, 5, 6}; / / OK// is non-aggregate, with user-provided constructor struct S3 {S3 () {} Int x; int y;}; std::array a3 {1, 2, 3, 4, 5, 6}; / / compilation failed!
Here you can see the subtle difference between the constructor of = default and the empty constructor.
Another story of std::initializer_list
All the rules mentioned above are valid only for aggregation initialization. If we add a constructor to the MyArray type that accepts std::initializer_list, the situation is different:
Struct S {int x; int y;}; templatestruct MyArray {public: MyArray (std::initializer_list l) {std::copy (l.begin (), l.end (), std::begin (data));} T data [N];}; int main () {MyArray a {{1,2}, {3,4}, {5,6} / / OK MyArray b {{1,2}, {3,4}, {5,6}}; / / same OK return 0;}
When initializing using std::initializer_list 's constructor, the initialization is successful regardless of whether the initialization list is surrounded by one or two curly braces, and the contents of an and b are exactly the same.
And why is that? Does std::initializer_list also support curly braces omission?
An interesting thing to mention here: when the book "Effective Modern C++" explains how to initialize objects, it gives such an example [2]:
Class Widget {public: Widget (); / / default ctor Widget (std::initializer_list il); / / std::initializer_list ctor... / / no implicit conversion funcs}; Widget w1; / / calls default ctorWidget w2 {}; / / also calls default ctorWidget w3 (); / / most vexing parse! Declares a function! Widget w4 ({}); / / calls std::initializer_list ctor with empty listWidget w5 {{}}; / / ditto
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.