Search code examples
c++member-initialization

Why can't member initializers use parentheses?


For example, I cannot write this:

class A
{
    vector<int> v(12, 1);
};

I can only write this:

class A
{
    vector<int> v1{ 12, 1 };
    vector<int> v2 = vector<int>(12, 1);
};

Why is there a difference between these two declaration syntaxes?


Solution

  • One possible reason is that allowing parentheses would lead us back to the most vexing parse in no time. Consider the two types below:

    struct foo {};
    struct bar
    {
      bar(foo const&) {}
    };
    

    Now, you have a data member of type bar that you want to initialize, so you define it as

    struct A
    {
      bar B(foo());
    };
    

    But what you've done above is declare a function named B that returns a bar object by value, and takes a single argument that's a function having the signature foo() (returns a foo and doesn't take any arguments).

    Judging by the number and frequency of questions asked on StackOverflow that deal with this issue, this is something most C++ programmers find surprising and unintuitive. Adding the new brace-or-equal-initializer syntax was a chance to avoid this ambiguity and start with a clean slate, which is likely the reason the C++ committee chose to do so.

    bar B{foo{}};
    bar B = foo();
    

    Both lines above declare an object named B of type bar, as expected.


    Aside from the guesswork above, I'd like to point out that you're doing two vastly different things in your example above.

    vector<int> v1{ 12, 1 };
    vector<int> v2 = vector<int>(12, 1);
    

    The first line initializes v1 to a vector that contains two elements, 12 and 1. The second creates a vector v2 that contains 12 elements, each initialized to 1.

    Be careful of this rule - if a type defines a constructor that takes an initializer_list<T>, then that constructor is always considered first when the initializer for the type is a braced-init-list. The other constructors will be considered only if the one taking the initializer_list is not viable.