According to the n4296 C++ standard document:
[dcl.init.list] (8.5.4.4) (pg223-224)
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. —end note ]
(emphasis mine)
The note was added here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1030
This reads to me that the following code:
#include <iostream> struct MyType { MyType(int i, int j, int k, int l) : sum(i + j + k + l) { } int sum; }; int main() { int i = 0; std::cout << MyType{ ++i, ++i, ++i, ++i }.sum << '\n'; }
Should print "10".
This is my reasoning:
That is to say, the above code should behave exactly like this code:
#include <initializer_list> #include <iostream> int main() { int i = 0; std::initializer_list<int> il{++i, ++i, ++i, ++i}; std::cout << *il.begin() + *(il.begin() + 1) + *(il.begin() + 2) + *(il.begin() + 3) << '\n'; }
But it does not. The first example prints '16' and the second example prints '10'
Literally every compiler from every vendor that I can get my hands on prints '16', seemingly ignoring that part of the standard and not inserting sequence points.
What am I missing here?
Note: The following seem to be related to this question:
Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.
Initialization lists. In fact, constructors should initialize as a rule all member objects in the initialization list.
Note: It is mandatory that a reference or a const member must be intialized in a constructor initialization list. They cannot be 'assigned' in the body of the constructor.
An initializer list starts after the constructor name and its parameters. The list begins with a colon ( : ) and is followed by the list of variables that are to be initialized – all of the variables are separated by a comma with their values in curly brackets.
The answer seems to be that yes, this is a bug in both GCC and MSVC.
This is the status of this issue:
My personal investigation, discussions with C++ experts at conferences, and unofficial answers I've received from compiler developers indicates that this is a bug in MSVC and GCC, but I'm always reluctant to answer my own questions on StackOverflow. But here we are.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With