Why C++11 In-Class Initializer Cannot Use Parentheses

Why C++11 in-class initializer cannot use parentheses?

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.

Why can in-class initializers only use = or {}? [duplicate]

I am not 100% positive about this, but this might be to prevent a syntax ambiguity. For example, consider the following class:

class BadTimes {
struct Overloaded;
int Overloaded; // Legal, but a very strange idea.

int confusing(Overloaded); // <-- This line
};

What does the indicated line mean? As written, this is a declaration of a member function named confusing that accepts as a parameter an object of type Overloaded (whose name isn't specified in the function declaration) and returns an int. If C++11 were to allow initializers to use parentheses, this would be ambiguous, because it could also be a definition of a member of type int named confusing that is initialized to the value of the data member Overloaded. (This is related to the current issue with the Most Vexing Parse.)

By requiring curly braces, this ambiguity is removed:

class BadTimes {
struct Overloaded;
int Overloaded; // Legal, but a very strange idea.

int confusing{Overloaded}; // <-- This line
};

Now, it's clear that confusing is actually an int initialized to the value of Overloaded, because there's no way to read it as a function declaration.

Hope this helps!

Why in-class initializer can't use ( ) [duplicate]

It is disallowed by the language. The reason is that there would be cases where it couldn't be disambiguated from a function declaration:

struct foo
{
int bar();
};

So instead of replicating the whole most vexing parse fiasco by allowing () to work sometimes, it is outright disallowed.

Why C++11 in-class initializer cannot use parentheses?

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.

Initialising in-class member with constructor arguments with round ( ) brackets? [duplicate]

A species of vexing parse. Names in default member initializers are supposed to be looked up in the completed class, because they are suppose to imitate constructor initializers. With (), the compiler won't be able to figure out what it's parsing, because it can refer to things declared later in the class:

struct X {
int f(x); // function or data member?
static const int x = 1;
};

Why I can't use constructor initializer list to initialize a in-class struct? [duplicate]

In your 2-param constructor, you can use aggregate initialization of the inner struct, eg:

test(int x, int y): _val(x), inclassobj{y}{}

Online Demo

In your second example, adding a constructor to the inner struct is fine, you just need to call it in the outer class's constructor member initialization list, eg:

test(int x, int y): _val(x), inclassobj(y){}

Online Demo

Initialization of member variable via parentheses doesn't work [duplicate]

There isnt actually much to explain, its just not valid syntax. Default member initializers are

class X
{
private:
int data{1}; // ok
int data2 = 42; // also ok

public:
void print()
{
cout << data << endl;
}
};

While int data(1); is not valid syntax for a default member initializer. See here for details: https://en.cppreference.com/w/cpp/language/data_members

most vexing parse prevents in-class initializing a std::vectorint [duplicate]

Default member initializers work with = as well. So

struct Foo{
std::vector<int> v = std::vector<int>(3);
};

Will do it. Though obviously, a major caveat is the fact that we are repeating the type name here.

We can alleviate it somewhat with decltype:

struct Foo{
std::vector<int> v = decltype(v)(3);
};

But that still has us naming things twice.



Related Topics



Leave a reply



Submit