Явный конструктор 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), даже если они не вызывали удаленный конструктор в предыдущем примере.

Другие вопросы по тегам