eca*_*mur 6 c++ crtp language-lawyer inheriting-constructors c++17
考虑:
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 接受bandxyz但拒绝aand c。MSVC 在 C++14 模式下拒绝所有,但在 C++17 模式下接受所有。
哪些编译器是正确的?C++14 和 C++17 之间的规则是否发生了变化——如果是这样,为什么在 C++14 中B::f不允许访问它自己的构造函数(命名为 via D)?为什么 Clang 只接受(函数式)强制转换 atb而不是列表初始化 ata或构造函数调用 at c?
(使Ba friendofD使 Clang 接受,除了旧版本(3.8 及更早版本)和 C++14 模式下的 MSVC。它对 gcc 没有影响。)
现在,我知道C++14 说:
如此声明的构造函数 [作为继承构造函数] 与 [基类] X 中的相应构造函数具有相同的访问权限。
在 C++17 中,规则被简化、澄清并移至 [namespace.udecl]:
命名构造函数的 using 声明符不会创建同义词;相反,如果附加构造函数在用于构造相应基类的对象时可访问,则它们是可访问的,并且忽略 using 声明的可访问性。
所以,我想也许“具有相同的访问权限”的意思继承构造函数private来D所以只能访问D(和它的朋友),而不是private到B(等访问B::f),因为是它们对应的中的构造B。但是在这种解释下,人们将能够通过继承来破坏访问检查和访问基类的私有构造函数。所以肯定在 C++14 中,措辞的意图与在 C++17 中更清楚地表达的意图相同 - 但是为什么 MSVC 会根据语言版本改变其行为?
继承构造函数(当时称为构造函数)的原始规范存在很多问题,其中几个涉及访问控制。它们是追溯性修复的,这应该仅适用于 C++14(作为当时最新发布的标准)。许多编译器选择将此类更改应用到有意义的早期版本(即C++11)。
\n然而,即使在已发布的 C++14 中,\xe2\x80\x99 也不可能访问私有基类构造函数,因为继承私有构造函数的隐式定义将无法调用基类中实际的私有构造函数。因此,除了未将缺陷报告应用于 C++14 之外,MSVC 是正确的;Clang 在处理某些类型的初始化时似乎有一个单独的错误;也许它接受,D(0)因为它\xe2\x80\x99s 定义为D \xe2\x80\xa6(0);. 当前的 GCC 在所有情况下都是正确的。
| 归档时间: | 
 | 
| 查看次数: | 91 次 | 
| 最近记录: |