【问题标题】:Access to own private constructors via derived class constructor inheritance通过派生类构造函数继承访问自己的私有构造函数
【发布时间】:2021-03-26 22:32:28
【问题描述】:

Consider:

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 接受 bxyz,但拒绝 ac。 MSVC 在 C++14 模式下拒绝所有,但在 C++17 模式下接受所有。

哪些编译器是正确的? C++14 和 C++17 之间的规则是否改变了 - 如果是这样,为什么在 C++14 中 B::f 不允许访问其自己的构造函数(通过 D 命名)?为什么 Clang 只接受 b 的(函数样式)强制转换,而不接受 a 的列表初始化或 c 的构造函数调用?

(使B 成为friendD 使Clang 接受,但旧版本(3.8 及更早版本)和C++14 模式下的MSVC 除外。它对gcc 没有影响。)

现在,我知道C++14 says

如此声明的[作为继承构造函数]的构造函数与[基类]X中的相应构造函数具有相同的访问权限。

而在 C++17 中,规则得到了简化、澄清和moved to [namespace.udecl]

命名构造函数的 using-declarator 不会创建同义词;相反,如果附加构造函数在用于构造相应基类的对象时可访问,则它们是可访问的,并且忽略 using 声明的可访问性。

所以,我认为也许“具有相同的访问权限”意味着继承的构造函数是 privateD 所以只有 D(及其朋友)可以访问,而不是 privateBB::f 可以访问),B 中对应的构造函数也是如此。但在这种解释下,人们可以通过继承来颠覆访问检查并访问基类的私有构造函数。所以可以肯定的是,在 C++14 中,措辞的意图与在 C++17 中更清楚地表达的意图相同——但是为什么 MSVC 会根据语言版本改变其行为呢?

【问题讨论】:

    标签: c++ c++17 language-lawyer crtp inheriting-constructors


    【解决方案1】:

    有一个lot of issues 具有继承构造函数的原始规范(因为它们当时被称为),其中一些涉及访问控制。它们是fixed retroactively,它应该是 C++14 的官方版本(作为当时最新发布的标准)。许多编译器选择将此类更改应用到有意义的更早版本(,C++11)。

    然而,即使在已发布的 C++14 中也无法访问私有基类构造函数,因为继承私有构造函数的隐式定义将无法调用实际的私有构造函数在基地。因此 MSVC 是正确的,只是没有将缺陷报告应用于 C++14; Clang 在处理某些类型的初始化时似乎有一个单独的错误;也许它接受D(0),因为它是根据D …(0); 定义的。当前的 GCC 在所有情况下都是正确的。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 2012-12-19
    • 1970-01-01
    • 2011-10-30
    • 2015-11-03
    • 2013-04-05
    • 1970-01-01
    相关资源
    最近更新 更多