struct A {};
struct B: A {
B(int);
B(B&);
B(A);
};
void foo(B);
void bar() {
foo(0);
}
#include <iostream>
struct A {
A() { std::cout << "A{}" << '\n'; }
A(const A&) { std::cout << "A(const A&)" << '\n'; }
};
struct B: A {
B(int) { std::cout << "B(int)" << '\n'; }
B(B&) { std::cout << "B(B&)" << '\n'; }
B(const B& b) : A(b) { std::cout << "B(const B&)" << '\n'; }
B(A) { std::cout << "B(A)" << '\n'; }
};
void foo(B) { std::cout << "foo(B)" << '\n'; }
int main() { foo(0); }
Both GCC and clang compile the code (see live example) printing:
A{}
B(int)
A(const A&)
B(const B&)
foo(B)which seems to be correct to me. VS2015 also compiles the code, but prints
A{}
B(int)
foo(B)because it always does copy elision, as far as I can understand.Therefore, all three compilers seem to be in agreement here. Now, let's comment out B's copy constructor.
#include <iostream>
struct A {
A() { std::cout << "A{}" << '\n'; }
A(const A&) { std::cout << "A(const A&)" << '\n'; }
};
struct B: A {
B(int) { std::cout << "B(int)" << '\n'; }
B(B&) { std::cout << "B(B&)" << '\n'; }
// B(const B& b) : A(b) { std::cout << "B(const B&)" << '\n'; }
B(A) { std::cout << "B(A)" << '\n'; }
};
void foo(B) { std::cout << "foo(B)" << '\n'; }
int main() { foo(0); }
Now GCC prints (live example)
A{}
B(int)
A(const A&)
A{}
B(A)
foo(B)and I have no idea where these: A{} and B(A) came from.clang fails to compile the code and VS2015 prints
A{}
B(int)
foo(B)
Which compiler is doing the right thing here and why?I'm particularly interested in knowing the quotes from the Standard supporting the answer. Thanks.
I'm experimenting with this snippet I found in DR 670
Now, let's comment out B's copy constructor.
#include <iostream>
struct A {
A() { std::cout << "A{}" << '\n'; }
A(const A&) { std::cout << "A(const A&)" << '\n'; }
};
struct B: A {
B(int) { std::cout << "B(int)" << '\n'; }
B(B&) { std::cout << "B(B&)" << '\n'; }
// B(const B& b) : A(b) { std::cout << "B(const B&)" << '\n'; }
B(A) { std::cout << "B(A)" << '\n'; }
};
void foo(B) { std::cout << "foo(B)" << '\n'; }
int main() { foo(0); }
Now GCC prints (live example)
A{}
B(int)
A(const A&)
A{}
B(A)
foo(B)and I have no idea where these: A{} and B(A) came from.
clang fails to compile the code
struct A { A(A const&) = delete; };
A f();
A const& a = f();
and VS2015 prints
A{}
B(int)
foo(B)
Which compiler is doing the right thing here and why?
I'm particularly interested in knowing the quotes from the Standard supporting the answer. Thanks.
First, gcc copy-initializes ([expr.call]/4, [dcl.init]/1, [dcl.init]/15, [dcl.init]/17]) a prvalue B from 0, printing A{} and B(int). It then direct-initializes ([dcl.init]/17) the parameter B from the prvalue B, enumerating all the constructors ([over.match.ctor]) with argument list prvalue B; the copy constructor is not viable (B& cannot bind to a prvalue: [over.match]/2, [over.match.viable]/3, [over.best.ics]/5, [over.ics.ref]/3), so as discussed in CWG 670 it selects B(A). The parameter A is direct-initialized from the prvalue B converted to A via derived-to-base conversion, selecting A(A const&) where the reference parameter is bound to the A subobject of an xvalue B materialized ([conv.rval]) from the prvalue B ([dcl.init.ref]/5), printing A(const A&); then B(A) prints A{} and B(A). We can now finally enter foo(B) and print foo(B).
when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same type (ignoring cv-qualification), the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move