Lately I ran into a problem which somehow (but only somehow) makes sense to me. It is based on interpreting the construction of a temporary as declaration of the single (!) constructor argument. Please have a look at the minimal example below.
#include <iostream>
class Foo0{
public:
Foo0(int a){};
void doStuff() {std::cout<<"maap"<<std::endl;};
};
class Foo1{
public:
Foo1(int a){};
void doStuff() {std::cout<<"maap"<<std::endl;};
};
class Foo2{
public:
Foo2(int a){};
void doStuff() {std::cout<<"maap"<<std::endl;};
};
class Bar{
public:
Bar(Foo0 foo0, Foo1 foo1, Foo2 foo2){};
};
int main () {
int x = 1;
Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’
Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF
Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF
Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’
Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me
x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious though.
}
I already read that expressions like:
Foo(a);
Are interpreted (if there is a standard constructor) as declaration of a. This makes sense and it is totally fine, since you can just use the {}-brackets to make the construction explicit. But what I do not understand is:
Why is there a problem with the construction of bar0?
All Foo
s do not have a standard constructor. So it does not make sense to interpret something like Foo0(x)
as declaration of x
.
Why does the construction of bar1
and bar2
work?
It is obvious to me that the construction of bar4
works, since I use the {}-brackets for all temporary Foo
s, thus I am explicit about what I want.
If it is only necessary to use the {}-brackets with only one of the Foo
s to solve the problem... why does the construction of bar3
fail?
Furthermore, x is declared before any Bar is constructed. Why does the compiler not complain about that?
The last question is related to my last line of example code. Long story short: What does the compiler think that I want him to do and where do I miss the appearance of shadowing?
PS: If it is of interest -- I use the gcc-4.9.2.
PPS: I tried the same with bar
's constructor taking three Foo0
s as arguments. Same story here. But the error says nothing about conflicting declaration but about redefinition of x
.
The rule is that if a declaration has the syntax of a function declaration then it is one; otherwise it is a variable declaration. Surprising instances of this are sometimes called most-vexing-parse.
Bar bar0(Foo0(x), Foo1(x), Foo2(x)); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’; conflicting declaration ‘Foo2 x’ previous declaration as ‘Foo0 x’
This is a function declaration: bar0
is the name, Bar
is the return type, and the parameter types are Foo0
, Foo1
and Foo2
. The parameter names are all x
which is illegal - the names of function parameters must be different. If you change x
x
x
to x
y
z
the error goes away).
Bar bar1(Foo0{x}, Foo1(x), Foo2(x)); // Works WTF
Bar bar2(Foo0(x), Foo1{x}, Foo2(x)); // Works WTF
Bar bar4(Foo0{x}, Foo1{x}, Foo2{x}); // Works totally makes sens to me
These lines and create objects bar1
, bar2
, and bar4
of type Bar
. They cannot be parsed as function declarations because the { }
notation is not valid syntax in a function declaration.
Therefore, Foo0{x}
etc. are expressions which provide the arguments to Bar
's constructor. Foo0{x}
and Foo0(x)
are equivalent ways of declaring a temporary of type Foo0
with initializer x
.
Bar bar3(Foo0(x), Foo1(x), Foo2{x}); // Does not work: conflicting declaration ‘Foo1 x’ previous declaration as ‘Foo0 x’
I think this is a compiler bug; the part Foo2{x}
means that this line cannot be a function declaration; and it looks like a valid declaration of a variable bar3
.
x.doStuff(); //Dose not work. This makes sens to me. But in the context its curious
x
is an int
; it does not have any methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With