通过派生 class 构造函数继承访问自己的私有构造函数
Access to own private constructors via derived class constructor inheritance
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
和 xyz
但拒绝 a
和 c
。
MSVC 在 C++14 模式下拒绝所有但在 C++17 模式下接受所有。
哪些编译器是正确的? C++14 和 C++17 之间的规则是否发生变化 - 如果是,为什么在 C++14 中 B::f
不允许访问其自己的构造函数(通过 D
命名)?为什么 Clang 只接受 b
处的(函数式)强制转换而不接受 a
处的列表初始化或 c
处的构造函数调用?
(使 B
成为 D
的 friend
使 Clang 接受,但旧版本(3.8 及更早版本)和 C++14 模式下的 MSVC 除外。它不会对 gcc 没有影响。)
现在,我知道 C++14 says:
A constructor so declared [as an inheriting constructor] has the same access as the corresponding constructor in [the base class] X.
并且在 C++17 中,规则被简化、阐明并且 moved to [namespace.udecl]:
A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored.
所以,我认为也许“具有相同的访问权限”意味着继承的构造函数是 private
到 D
,所以只有 D
(及其朋友)可以访问,而不是比 private
到 B
(因此 B::f
可以访问)以及它们在 B
中的相应构造函数。但是在这种解释下,人们将能够通过继承来破坏访问检查并访问一个人的基础 class 的私有构造函数。因此,在 C++14 中,措辞的意图肯定与在 C++17 中更清楚地表达的相同——但是为什么 MSVC 会根据语言版本改变其行为?
有一个 lot of issues with the original specification of inheriting constructors (as they were then called), several of which involved access control. They were fixed retroactively,它应该是仅适用于 C++14 的官方标准(作为当时最新发布的标准)。许多编译器 选择 将此类更改应用到有意义的早期版本( 即 、C++11)。
但是,即使在已发布的 C++14 中,也无法访问私有基础-class 构造函数,因为继承私有构造函数的隐式定义会失败 来调用基类中的实际私有构造函数。因此,除了不将缺陷报告应用于 C++14 之外,MSVC 是正确的; Clang 在处理某些类型的初始化时似乎有一个单独的错误;也许它接受 D(0)
因为它是根据 D …(0);
定义的。当前的 GCC 在所有情况下都是正确的。
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
和 xyz
但拒绝 a
和 c
。
MSVC 在 C++14 模式下拒绝所有但在 C++17 模式下接受所有。
哪些编译器是正确的? C++14 和 C++17 之间的规则是否发生变化 - 如果是,为什么在 C++14 中 B::f
不允许访问其自己的构造函数(通过 D
命名)?为什么 Clang 只接受 b
处的(函数式)强制转换而不接受 a
处的列表初始化或 c
处的构造函数调用?
(使 B
成为 D
的 friend
使 Clang 接受,但旧版本(3.8 及更早版本)和 C++14 模式下的 MSVC 除外。它不会对 gcc 没有影响。)
现在,我知道 C++14 says:
A constructor so declared [as an inheriting constructor] has the same access as the corresponding constructor in [the base class] X.
并且在 C++17 中,规则被简化、阐明并且 moved to [namespace.udecl]:
A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored.
所以,我认为也许“具有相同的访问权限”意味着继承的构造函数是 private
到 D
,所以只有 D
(及其朋友)可以访问,而不是比 private
到 B
(因此 B::f
可以访问)以及它们在 B
中的相应构造函数。但是在这种解释下,人们将能够通过继承来破坏访问检查并访问一个人的基础 class 的私有构造函数。因此,在 C++14 中,措辞的意图肯定与在 C++17 中更清楚地表达的相同——但是为什么 MSVC 会根据语言版本改变其行为?
有一个 lot of issues with the original specification of inheriting constructors (as they were then called), several of which involved access control. They were fixed retroactively,它应该是仅适用于 C++14 的官方标准(作为当时最新发布的标准)。许多编译器 选择 将此类更改应用到有意义的早期版本( 即 、C++11)。
但是,即使在已发布的 C++14 中,也无法访问私有基础-class 构造函数,因为继承私有构造函数的隐式定义会失败 来调用基类中的实际私有构造函数。因此,除了不将缺陷报告应用于 C++14 之外,MSVC 是正确的; Clang 在处理某些类型的初始化时似乎有一个单独的错误;也许它接受 D(0)
因为它是根据 D …(0);
定义的。当前的 GCC 在所有情况下都是正确的。