Явный конструктор C++, вызываемый в неявной ситуации
Я скомпилировал код ниже, используя g++ 6.3.0, с опцией -std= C++14.
#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
}
Я ожидал, что это выведет "1!" поскольку преобразование неявное, но оно выдает "2!". Если я закомментирую конструктор шаблона, он не скомпилируется. Это правильное поведение, или это какая-то ошибка в g ++?
1 ответ
Да, ваша программа должна печатать
1!
.
Упрощенная версия программы, показывающая расхождение компилятора:
struct B {
int b;
constexpr B(auto) { b = 1; }
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr B b = 0;
static_assert( b.b == 1 ); //ok everywhere
constexpr C c = 0;
static_assert( c.b == 1 ); //ok in Clang only
Демо: https://gcc.godbolt.org/z/hva4f5qs5
Как указано в соответствующей ошибке GCC https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85251 : [namespace.udecl] p13 указывает, что здесь должно произойти:
Конструкторы, названные с помощью объявления использования, рассматриваются как конструкторы производного класса при поиске конструкторов производного класса ([class.qual]) или формировании набора кандидатов на перегрузку ([over.match.ctor], [over.match.copy], [over.match.list]).
Итак, конструктор из
B
останется
explicit
в
C
после
using B::B;
, и только Clang в данный момент корректно обрабатывает вышеуказанную программу.
И еще более простой способ увидеть, что другие компиляторы ошибаются, это удалить
B(auto)
конструктор:
struct B {
int b;
constexpr explicit B(int) { b = 2; }
};
struct C : B {
using B::B;
};
constexpr C c = 0; // error everywhere
Теперь все компиляторы правильно отклоняют код (демо: https://gcc.godbolt.org/z/P3zqxMvvn), даже если они не вызывали удаленный конструктор в предыдущем примере.