I'm confused about Y y {X{}}; what exactly this line does and what is its connection to the most vexing parse. A brief explanation is appreciated:
#include <iostream>
struct X {
X() { std::cout << "X"; }
};
struct Y {
Y(const X &x) { std::cout << "Y"; }
void f() { std::cout << "f"; }
};
int main() {
Y y { X{} };
y.f();
}
what exactly this line does
It creates a temporary X, value-initialising it by calling the default constructor, and then uses that to initialise a Y variable, calling the const X& conversion constructor.
where is connection to Most vexing parse
If you were to try to write this using old-school initialisation syntax
Y y (X());
then the so-called "most vexing parse" would interpret this as a function, rather than a variable, declaration: a function called y, with return type Y and a single parameter, whose type is a (pointer to a) function returning X.
You could add extra parentheses, so that it can't be interpreted as a function declaration:
Y y ((X()));
or, since C++11, you can use brace-initialisation as your example does.
Y y { X{} };
This is perfect and creates an object y passing a temporary object of type X to the constructor. There is NO vexing parse (most or otherwise). In fact, the construction using {} was introduced to solve the issue of vexing parse in many cases, such as these:
Y y1();
Y y2(X());
Both belongs to (most) vexing parse because of which both declares functions, instead of objects.
However, if you use curly braces called brace-initialization:
Y y1{};
Y y2{ X{} }; //as you've done yourself
then both declares objects, not functions, as expected.
Related
Why does the compiler interpret this line as a function definition and not as a variable definition:
Y y(X());
in the following code:
#include <iostream>
struct X {
X() { std::cout << "X"; }
};
struct Y {
Y(const X &x) { std::cout << "Y"; }
void f() { std::cout << "f"; }
};
int main() {
Y y(X());
y.f();
}
VS2010 gives the following error on line "y.f();"
left of '.f' must have class/struct/union
Which part of the standard describes this behavior?
The answer to the following question doesn't give details about it:
Most vexing parse
Consider this :
float foo( int () )
This declares a function foo ( accepting a function returning int ) returning float.
Now read
Y y(X());
as y as function (accepting a function returning X) returning Y
The problem arises due to C++ most vexing parse
Can be solved with :
Y y{ X() }; // requires C++11
or
Y y( ( X() ) );
// ^ ^ notice parenthesis
Update based on edit:
A quote from the standard :
§ 8.2 Ambiguity resolution [dcl.ambig.res]
1 - The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration. [Note: a declaration can be explicitly disambiguated by a nonfunction-style cast, by a = to indicate initialization or by removing the redundant parentheses around the parameter name. ]
[Example:
struct S {
S(int);
};
void foo(double a)
{
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
—end example]
Similarly other examples following this.
Most vexing parse problem. Y y(X()) is actually function declaration with name y, that returns Y and receives argument of type function, that returns X and receives nothing.
It's solved in C++11 with usage of {} for construct object.
I have this small piece of code that doesn't compile, and I was wondering about the reasons more specifically why is push(new X) the problem?
Before that, I would like to ask what new X (with no identifier) really mean? does it create an object X with no identifier name? does it go through the constructor at all?
Secondly,
I might not understand the whole concept, but, push is a template class, right?
Since it contains a static T stack, the type T is consistent and can not be changed once a specific argument is sent, the first one, in this case int x. Is that correct?
Thirdly,
following my second question, if it is correct then why push(y) do not flag a compiler error just like push(new X) does? i mean, x is an int type and y is a reference type.
I'd really appreciates if someone can clarify it for me.
Thanks, here it is:
#include <iostream>
using namespace std;
template <class T>
void push(T &t) {
static const int CAPACITY = 20;
static T stack[CAPACITY];
static int size = 0;
stack[size++] = t;
cout << size;
};
class X {};
void main()
{
int x = 3;
int &y = x;
push(x);
push(new X);
push(y);
}
and I was wondering about the reasons more specifically why is push(new X) the problem?
Because you declared type of your template function parameter as non const lvalue reference to T. To help programmers to avoid incorrect code language does not allow to bind temporaries to non const lvalue references. In your case:
new X
returns a temporary of type X * (pointer to X), your template function argument type T deduced to X * in this case and t is now lvalue reference to X * or X *& but language does not allow to bind temporary to an lvalue reference hense compilation error. Your second case is logically equal to this code:
void pushX( X *&t ); // pushX accepts reference to pointer to X
pushX( new X ); // you cannot bind a temporary returned by `new X` to lvalue reference `t`
It could be easier to understand if you use simple type like int:
int function_returns_int();
void push_int( int &ri );
push_int( function_returns_int() ); // compilation error, function_returns_int() returns temporary
You can make your code compile if you store pointer in a variable and make it non-temporary:
int main() // main() must have return type int not void
{
int x = 3;
int &y = x;
push(x);
X *px = new X;
push(px);
push(y);
delete px;
}
but most probably you chosen wrong type for the argument.
Details about references and why you can pass int &y and why t would not be a reference to reference in this case you can find here
Note: your code if you make it compile (changing type of t to const reference for example) would lead to memory leak, but that is out of scope of your question
class A {
public:
int a;
char b;
double c;
A ( int x, char y, double z ) : a(x), b(y), c(z){}
};
int main(){
auto lambda = []( auto x ) {
static auto y = x;
// y = x;
return y;
};
int a = lambda(1);
char b = lambda('a');
double c = lambda(1.5);
A d = lambda( A( 2, 'b', 2.5 ) );
return 0;
}
This code compiles in Clang 3.8.0 and GCC 5.4.0, and works fine. However, taking into account that variable y is static:
What is the type of variable y? Does the type of y change in every call to the lambda?
Is variable y initialized in every call in spite of being static? The commented assignment // y = x is not needed to update the value of variable y.
Is this behaviour C++14 Standard compliant?
If I print the sizeof(y) in each call I get 4, 1, 8 and 16 respectively.
On local and global static variables in C++
Your lambda is generic. Which means that this is a template in disguise. The situation is handled in accordance with general rules for template specializations.
For every specific deduced type of parameter x you get a separate specialization of your function. So, yes for each specific type of x you get a separate copy of y. But the underlying mechanism is not somehow localized at your static, it is the whole body of your function that gets "copied" to produce a separate independent implementation of the function.
Each specialization of your lambda will have a separate copy of y, which will be initialized only once at the first call to that specific specialization.
The situation is virtually equivalent to a more explicit
template <typename T> void foo(T x)
{
static T y = x;
std::cout << y << std::endl;
}
int main()
{
foo(1);
foo('a');
foo(1.5);
foo(3.0);
}
which outputs 1, a, 1.5 and 1.5.
In this example you get three independent specializations of foo: foo<int>, foo<char> and foo<double>. Each version of foo gets its own version of y, meaning that there are three different static ys in this example. The first call to each specialization will initialize y and the subsequent calls will not re-initialize it. In this case call to foo(1.5) initializes y for foo<double>, but the subsequent call to foo(3.0) does not.
The same thing happens in your case as well, it just uses a different syntax.
Lamda with auto is nothing more than a class with operator () overloaded to be a template and using auto for type deduction (which follows the rules for a template parameter deduction).
In this case you have as many static y fields as many instantiations of this function object template operator.
The initialization is done like in hand written class which is the first time the function is triggered (the lambda in this case)
I'm confused about Y y {X{}}; what exactly this line does and what is its connection to the most vexing parse. A brief explanation is appreciated:
#include <iostream>
struct X {
X() { std::cout << "X"; }
};
struct Y {
Y(const X &x) { std::cout << "Y"; }
void f() { std::cout << "f"; }
};
int main() {
Y y { X{} };
y.f();
}
what exactly this line does
It creates a temporary X, value-initialising it by calling the default constructor, and then uses that to initialise a Y variable, calling the const X& conversion constructor.
where is connection to Most vexing parse
If you were to try to write this using old-school initialisation syntax
Y y (X());
then the so-called "most vexing parse" would interpret this as a function, rather than a variable, declaration: a function called y, with return type Y and a single parameter, whose type is a (pointer to a) function returning X.
You could add extra parentheses, so that it can't be interpreted as a function declaration:
Y y ((X()));
or, since C++11, you can use brace-initialisation as your example does.
Y y { X{} };
This is perfect and creates an object y passing a temporary object of type X to the constructor. There is NO vexing parse (most or otherwise). In fact, the construction using {} was introduced to solve the issue of vexing parse in many cases, such as these:
Y y1();
Y y2(X());
Both belongs to (most) vexing parse because of which both declares functions, instead of objects.
However, if you use curly braces called brace-initialization:
Y y1{};
Y y2{ X{} }; //as you've done yourself
then both declares objects, not functions, as expected.
Simple question about C++11 syntaxis. There is a sample code (reduced one from source)
struct Wanderer
{
explicit Wanderer(std::vector<std::function<void (float)>> & update_loop)
{
update_loop.emplace_back([this](float dt) { update(dt); });
}
void update(float dt);
};
int main()
{
std::vector<std::function<void (float)>> update_loop;
Wanderer wanderer{update_loop}; // why {} ???
}
I'd like to know, how it can be possible call constructor with curly brackets like Wanderer wanderer{update_loop}; It is neither initializer list, nor uniform initialization. What's the thing is this?
It is neither initializer list, nor uniform initialization. What's the thing is this?
Your premise is wrong. It is uniform initialization and, in Standardese terms, direct-brace-initialization.
Unless a constructor accepting an std::initializer_list is present, using braces for constructing objects is equivalent to using parentheses.
The advantage of using braces is that the syntax is immune to the Most Vexing Parse problem:
struct Y { };
struct X
{
X(Y) { }
};
// ...
X x1(Y()); // MVP: Declares a function called x1 which returns
// a value of type X and accepts a function that
// takes no argument and returns a value of type Y.
X x2{Y()}; // OK, constructs an object of type X called x2 and
// provides a default-constructed temporary object
// of type Y in input to X's constructor.
It is just C++11 syntax. You can initialize objects calling their constructor with curly braces. You just have to bear in mind that if the type has an initializer_list constructor, that one takes precedence.
In addition, braces-constructors do not allow narrowing, similarly to braces-initialization.
Let's take a look at the simple constructor taking and printing an integer value:
class Test {
public:
Test(int i) {
std::cout << i << std::endl;
}
};
While Test test(3.14); compiles and outputting narrowed 3,
Test test{3.14}; would not even compile:
error: narrowing conversion of ‘3.1400000000000001e+0’ from ‘double’ to ‘int’ [-Wnarrowing]
11 | Test test{3.14};
| ^