Yu Ding
Yu Ding

Reputation: 41

Initializer in braces and parentheses - From Item 7 in Modern Effective C++

In Chapter7, Item 7 of the book "Effective Modern Cpp", differences between () and {} when creating objects are discussed. However, when I compiled and run some code listed in the chapter, I found that the code behaved different from what the comment had described. I have to address that the code I used for testing was written by me and thus not exactly the same as the original code in the book, but it's simpler and would be enough to cover my point. And I am quite positive that the differences wouldn't be the cause of the problem I encountered.

The location of the content of interest in the book which is in PDF format is Item 7, page 53.

At the end of this page, the comments to the code "Widget w6{w4};", said that "uses braces, calls std::initializer_list ctor (w4 converts to float, and float converts to long double)". Then, I wrote my code below just for a regular verification, I wasn't expecting anything unordinary until I saw the output of the code.

#include <iostream>

using namespace std;

class Widget {
public:
    Widget(int i) : _i(i){
        cout << "call to Widget(int i)" << endl;
    }
    Widget(Widget& w) {
        _i = w._i;
        cout << "call to Widget(Widget& w)" << endl;
    }

    Widget(initializer_list<int> il) {
        if (il.size() > 0) {
            _i = *(il.begin());
        }

        cout << "call to Widget(initializer_list<int> il)" << endl;
     }

    void print_info() {
        cout << "_i: " << _i << endl;
    }

    operator int() const {
        // return a fixed value just for testing
        return 100;
    }

    private:
        int _i;
};

// this is the testbed
int main() {
    Widget w1{10, 5};
    w1.print_info();

    cout << "----------------------------------------" << endl;

    Widget w2{{w1}};
    w2.print_info();

    cout << "----------------------------------------" << endl;
    Widget w3{w1};
    w3.print_info();
    return 0;
}

The output of the code is like

 ~/CppTest/move_construct  g++ -std=c++17 -o run test.cpp                                    ✔  11:49:11
 ~/CppTest/move_construct  ./run                                                             ✔  11:49:26
call to Widget(initializer_list<int> il)
_i: 10
----------------------------------------
call to Widget(initializer_list<int> il)
_i: 100
----------------------------------------
call to Widget(Widget& w)
_i: 10

As you can see, the initialization of w2 using braced initialization with w1 being wrapped within another layer of braces, behaves exactly as the comments in the book have said. But w3, which is initialized using a single layer of braces, is just copy-constructed.

I don't know if this is caused by the evolution of compilers, the cpp standards or some kind of compiler configurations I ignored. The info of the compiler I am using is:

Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin21.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Thanks and looking forward to your answers.

Upvotes: 1

Views: 126

Answers (1)

user17732522
user17732522

Reputation: 76628

When the book was probably written it was correct in that the std::initializer_list constructor should be preferred over the copy constructor.

However then the rules were changed with CWG 1467 with the effect that the copy constructor would be preferred.

However, this was probably just an unintended side effect since the rules were meant to just fix the behavior of aggregate classes, so CWG 2137 again modified the rules with the effect that the std::initializer_list constructor would be preferred as was the original behavior.

You seem to be using Clang, which happens to not have implemented the latter defect report yet, see this open bug report.

So in the end the book is still correct, but the compiler has not kept up with the rule changes.

GCC produces the expected output. MSVC interestingly has an internal compiler error (so also a bug) when trying to compile your code: https://godbolt.org/z/TKcEzn1be

Upvotes: 1

Related Questions