C++ MSVC 19删除继承的构造函数

C++ MSVC 19删除继承的构造函数,c++,c++11,visual-c++,C++,C++11,Visual C++,在MSVC19.16下,如果类B显式地从类A继承构造函数,并且还定义了自己的构造函数,那么继承的构造函数将被忽略 class A { public: A() {} A(int x) {} }; class B : public A { public: using A::A; B(double x) : A() {} }; int main() { B b; // error C2512: 'B': no appropr

在MSVC19.16下,如果类B显式地从类A继承构造函数,并且还定义了自己的构造函数,那么继承的构造函数将被忽略

class A {
public:
    A() {}
    A(int x) {}
};

class B : public A {
public:
    using A::A;

    B(double x) : A() {}
};

int main()
{
    B b;                 // error C2512: 'B': no appropriate default constructor available
                         // note: see declaration of 'B'
    return 0;
}
在gcc下正确编译。
有人知道这是编译器错误还是我遗漏了什么吗?谢谢。

如果我们指定
/std:c++14
,它仍然会编译时出错。但是
/std:c++17
/std:c++latest
使其可编译。
所以它看起来像是MSVC中的一个bug。

我想它是MSVC 19.16编译器的bug

如果你写信

class B : public A {
    B(double) : A() {}
};

// ...

B b;
您应该从每个编译器得到一个错误,因为
B(double)
构造函数删除了默认的
B()
构造函数

但是,根据(寻找“继承构造函数”)

如果using声明引用所定义类的直接基的构造函数(例如using base::base;),则在初始化派生类时,该基的所有构造函数(忽略成员访问)对重载解析都是可见的

如果重载解析选择了一个继承的构造函数,那么如果该构造函数在用于构造相应基类的对象时是可访问的,则该构造函数是可访问的:引入它的using声明的可访问性将被忽略

如果重载解析在初始化此类派生类的对象时选择了一个继承的构造函数,则继承构造函数的基子对象将使用继承的构造函数进行初始化,而派生类的所有其他基和成员将如同由默认的默认构造函数初始化一样进行初始化(如果提供了默认成员初始值设定项,则使用默认成员初始值设定项,否则将进行默认初始化)。整个初始化被视为单个函数调用:在初始化派生对象的任何基或成员之前,对继承构造函数的参数进行初始化

因此,在这种情况下,使用A::A;声明的
应该转换
B
构造函数中的
A
构造函数

另一个例子

仅使用接收
std::string
的构造函数定义
B

class B : public A {
public:
    using A::A;
    
    B(std::string) : A() {}
};
应该可以使用整数初始化
B

B  b(1);
因为
A(int)
构造函数是作为
B
构造函数继承的。

可以说不是一个bug

C++14[class.inhctor]3

对于继承构造函数的候选集中的每个非模板构造函数,除了没有参数的构造函数或只有单个参数的复制/移动构造函数之外,都会隐式声明具有相同构造函数特征的构造函数

因此,在C++17之前,默认构造函数是不可继承的,并且您的示例格式不正确

当删除整个[class.inhctor]部分并将继承构造函数的措辞改为[namespace.udecl]时,情况发生了变化。这一点被投票选为C++17,但由于这是缺陷解决方案的一部分,实现也被允许追溯到标准的以前版本

因此,您的示例是有效的C++17,并且可能是有效的C++11和C++14,这取决于您的编译器供应商在根据这些标准修订版进行编译时是否选择追溯应用此更改。合格的编译器在以C++17模式编译时必须接受此示例,并且有权接受或拒绝此更改s在C++11或C++14模式下编译时的示例,具体取决于供应商的决定

也可能是相关的


请注意,在您的示例中,MSVC 19.16只忽略了
A::A()
。它既不忽略
A::A(int x)
,也不忽略clang。@IgorTandetnik似乎是使用GCC 7.x或更高版本,或clang 6.x或更高版本编译的:@ΦXocę웃Пepeúpaツ 它是
A(){}
因为他们使用
使用A::A;
不太确定这是一个bug。
B
有一个用户定义的c'tor。它应该抑制默认构造函数的生成。那么为什么using声明应该改变这一点呢?这确实会使程序编译,尽管它不是一个解决方案。它可能是编译器中的一个bug,因为它应该编译无论如何,谢谢。好的,谢谢,这澄清了这一点。但是:为什么只有定义了
B::B(double)
时才会发生这种情况?(可能我忘了在我的报告中提到这一点)@HappyCactus如果
B
没有用户声明的构造函数,那么
B::B()
由编译器隐式声明。继承不会影响这一点。