【问题标题】:C++ namespace collision in copy constructor复制构造函数中的 C++ 命名空间冲突
【发布时间】:2020-03-24 07:56:26
【问题描述】:

我有以下代码:

namespace A {
    struct Foo {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};

C++ 编译器抱怨“c = foo.b”,因为 A::Foo 没有名为 b 的成员。 如果我使用 ::Foo 更改 Bar 参数的类型,它会起作用。

我的问题是这种行为背后的原因是什么(我想这与继承使 Bar 进入 A 命名空间这一事实有关,但我找不到任何文档来支持这一理论。

【问题讨论】:

  • 认为它与参数相关的查找相关。我已将“语言律师”标记为“语言律师”,因为我认为您正在寻找参考语言标准的答案。第一个问题非常好!让这一切都值得。
  • 它没有进入命名空间A,如果你让Bar继承A中的另一个结构,你可以看到。那么就没有歧义了。它更像是继承添加了从A::FooBar 的所有内容,包括FooA::Foo 的分辨率。抱歉,我真的无法更准确地表达。
  • @Bathsheba 你的意思是在模板中查找函数名称(或函数模板名称)或依赖名称的参数类型依赖名称查找吗?

标签: c++ inheritance namespaces language-lawyer


【解决方案1】:

每个类都将其名称作为成员注入其中。所以你可以命名A::Foo::Foo。这称为注入的类名。

[类]

2 类名被插入到声明它的作用域中 在看到类名之后立即。类名也是 插入到类本身的范围内;这被称为 注入类名。出于访问检查的目的, injection-class-name 被视为公共成员名称。

[basic.lookup]

3一个类的注入类名也被认为是一个 该类的成员,用于名称隐藏和查找。

因为参数类型的非限定名称查找开始于类Bar 的范围内,它将继续进入其基类的范围以解释那里的任何成员。它会找到A::Foo::Foo 作为类型名称。

如果您想使用全局类型名称,只需通过其周围的(全局)命名空间对其进行限定。

Bar(::Foo foo) {
    c = foo.b;
}

在注入的类名没有出现的范围内进行完全限定的查找。

有关“为什么”的后续问题,请参阅

【讨论】:

  • @TedLyngmo - ADL 发生在函数调用中,与这些特定段落无关。
  • 这导致了非常有趣的struct Bar:: A::Foo::Foo::Foo::Foo::Foo {};there are contexts 其中A::Foo::Foo 指定构造函数,因此您不能继续添加任意数量的Foo。这类似于(但机制完全不同)您可以通过这种方式调用函数f(************f)()
  • @AProgrammer - 确实。甚至可以构造more amusing examples
  • 这个答案肯定解释了“什么”。可以改进添加“为什么”吗?比如,这条规则的目的是什么?它改进了哪些用例或使哪些用例成为可能?
  • @davidbak - 为什么?为什么有一个注入的类名?那不是这个问题的一部分。但肯定是this one的主题。
【解决方案2】:

不是一个完整的答案,只有代码显示(因为它编译)Bar 没有输入namespace A。您可以看到,当从A::Foo1 继承时,Foo 的歧义性没有问题,如果这种继承让Bar 输入A,则会有所不同。

namespace A {
    struct Foo {
        int a;
    };

    struct Foo1 {
        int a;
    };
}

struct Foo {
    int b;
};

struct Bar : public A::Foo1 {
    Bar(Foo foo) {
        c = foo.b;
    }
    int c;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-06
    • 2012-12-18
    • 2020-04-23
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    相关资源
    最近更新 更多