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
How to Take Input String Till End of Line in C++ Without the Use of Getline
Finding Version of Microsoft C++ Compiler from Command-Line (For Makefiles)
How to Remove "Noise" from Gcc/Clang Assembly Output
How to Read and Parse CSV Files in C++
Difference Between Function Template and Template Function
Automatically Refreshing a Qtableview When Data Changed
What Does the Single Ampersand After the Parameter List of a Member Function Declaration Mean
How to Peek At the Next Element in a Range-For Loop
Checking If All Elements of a Vector Are Equal in C++
While Writting Unittests for a Function, Should I Mock the Internal Function Calls Made
Carry Over Data Without Using for Loop
How to Properly Add Include Directories With Cmake
How to Tokenize a String in C++
What Are Forward Declarations in C++
Print Heart Shape With Words Inside
Checking the Neighbour Values of Arrays
Given an Integer N. What Is the Smallest Integer Greater Than N That Only Has 0 or 1 as Its Digits