I compiled the code below using g++ 6.3.0, with -std=c++14 option.
#include <utility>
#include <iostream>
struct A{
int x;
A(const A&)=default;
A(int x):x(x){}
};
struct B{
A a;
template<class... Args>
B(Args&&... args):a(std::forward<Args>(args)...){
std::cout<<"1!"<<std::endl;
}
explicit B(const A& a):a(a){std::cout<<"2!"<<std::endl;}
};
struct C:B{
using B::B;
};
int main(){
A a{2};
const A& aref=a;
C c=aref; //Implicit conversion
}
I expected it to output "1!" since the conversion is implicit, but it output "2!". If I comment out the template constructor, it will not compile. Is this the correct behavior, or is this some kind of g++ bug?
Yes, your program shall print
1!
.A simplified version of the program showing compiler divergence is
Demo: https://gcc.godbolt.org/z/hva4f5qs5
As quoted in related GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85251 : [namespace.udecl] p13 does specify what should happen here:
So
explicit
constructor fromB
shall remainexplicit
inC
afterusing B::B;
, and only Clang correctly process the above program at this moment.And even easier way to see that other compilers are wrong, is to remove
B(auto)
constructor:Now all compilers correctly reject the code (demo: https://gcc.godbolt.org/z/P3zqxMvvn) even though they did not call the removed constructor in the previous example.