通过派生 class 构造函数继承访问自己的私有构造函数

Access to own private constructors via derived class constructor inheritance

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 成为 Dfriend 使 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.

所以,我认为也许“具有相同的访问权限”意味着继承的构造函数是 privateD,所以只有 D(及其朋友)可以访问,而不是比 privateB(因此 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 在所有情况下都是正确的。