gpt4 book ai didi

c++ - 在类里面, `using Base::BaseOfBase;` 应该做什么?

转载 作者:行者123 更新时间:2023-12-01 13:37:58 24 4
gpt4 key购买 nike

考虑这段代码:

#include <iostream>
#include <type_traits>

struct A
{
A(int x) {std::cout << "A(" << x << ")\n";}
};

struct B : A
{
using A::A;
B(int x, int y) : A(x) {std::cout << "B(" << x << "," << y << ")\n";}
};

struct C : B
{
using B::A; // <--

// C() : B(0,0) {}
};

int main()
{
C c(1);
}
gcc.godbolt.org
它在 GCC 上编译并打印 A(1) ,这意味着 B 的实例在没有调用构造函数的情况下被“构造”。如果您取消注释 C() ,然后 C c(1);不再编译(GCC 找不到合适的构造函数)
Clang 什么也没说 using B::A; ,但拒绝编译 C c(1); (也找不到合适的构造函数)。
MSVC 停在 using B::A; ,基本上是说你只能从直接基类继承构造函数。
Cppreference没有提到从间接基础继承构造函数,所以它似乎是不允许的。
是 GCC 和 Clang 错误,还是这里发生了什么?

最佳答案

构造函数不是继承的。主要是因为

[namespace.udecl]

3 In a using-declaration used as a member-declaration, eachusing-declarator's nested-name-specifier shall name a base class ofthe class being defined. If a using-declarator names a constructor,its nested-name-specifier shall name a direct base class of the classbeing defined.


但更重要的是 B::A甚至根本没有命名构造函数。

[class.qual]

2 In a lookup in which function names are not ignored and thenested-name-specifier nominates a class C:

  • if the name specified after the nested-name-specifier, when looked up in C, is the injected-class-name of C (Clause [class]), or
  • in a using-declarator of a using-declaration that is a member-declaration, if the name specified after thenested-name-specifier is the same as the identifier or thesimple-template-id's template-name in the last component of thenested-name-specifier,

the name is instead considered to name the constructor of class C.[ Note: For example, the constructor is not an acceptable lookupresult in an elaborated-type-specifier so the constructor would not beused in place of the injected-class-name.  — end note ] Such aconstructor name shall be used only in the declarator-id of adeclaration that names a constructor or in a using-declaration.[ Example:

struct A { A(); };
struct B: public A { B(); };

A::A() { }
B::B() { }

B::A ba; // object of type A
A::A a; // error, A​::​A is not a type name
struct A::A a2; // object of type A

 — end example ]


上述两个项目符号都不适用。所以 B::A不是构造函数的名称。只是注入(inject)的类名 A ,已经可以在 C 中使用.我想这应该就像从基类中引入任何旧的类型定义一样。 IE。 Clang会让你定义
C::A a(0);
这看起来是正确的。唯一的用途是如果 B继承自 protected A .在这种情况下,默认情况下注入(inject)的类名也是不可访问的,直到使用 using 声明。在 godbolt 上修改您的示例确认它。
MSVC 可能过于热衷于彻底拒绝此代码。
至于哪个编译器是正确的,C++20引入了 aggregate initialization via parenthesized list of values . C是一个聚合,所以 C c(1);实际上是聚合初始化 c通过使用 1复制初始化 B子对象。所以 C不需要继承构造函数使此代码有效。
GCC 确实在这样做(因为使 c'tors 显式使它拒绝代码),而 Clang 似乎没有实现 P0960然而。

关于c++ - 在类里面, `using Base::BaseOfBase;` 应该做什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62109026/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com