考虑:
struct B {
void f();
private:
B(int, int = 0);
};
struct D : B { using B::B; };
void B::f() {
auto a = D{0};
auto b = D(0);
auto c = D(0, 0);
D x{0};
D y(0);
D z(0, 0);
}
GCC 接受(从 7.1 开始;以前全部拒绝)。Clang 接受b
andxyz
但拒绝a
and c
。MSVC 在 C++14 模式下拒绝所有,但在 C++17 模式下接受所有。
哪些编译器是正确的?C++14 和 C++17 之间的规则是否发生了变化 - 如果是这样,为什么在 C++14 中B::f
不允许访问其自己的构造函数(通过命名D
)?为什么 Clang 只接受 (function-style) cast atb
而不是 list-initialization ata
或构造函数调用 at c
?
(制作B
afriend
会使D
Clang 接受,但旧版本(3.8 和更早版本)和 C++14 模式下的 MSVC 除外。它对 gcc 没有影响。)
现在,我知道C++14 说:
如此声明的构造函数 [作为继承构造函数] 与 [基类] X 中的相应构造函数具有相同的访问权限。
在 C++17 中,规则被简化、澄清并移至 [namespace.udecl]:
命名构造函数的 using-declarator 不会创建同义词;相反,如果附加构造函数在用于构造相应基类的对象时可访问,则它们是可访问的,并且忽略 using 声明的可访问性。
所以,我认为也许“具有相同的访问权限”意味着继承的构造函数private
只能D
访问D
(及其朋友),而不是(并且private
可以B
访问B::f
),因为它们在B
. 但是在这种解释下,人们可以通过继承来颠覆访问检查并访问基类的私有构造函数。所以可以肯定的是,在 C++14 中,措辞的意图与在 C++17 中更清楚地表达的意图相同——但是为什么 MSVC 会根据语言版本改变其行为呢?