复制构造函数中的C ++名称空间冲突


33

我有以下代码:

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名称空间这一事实有关,但是我找不到任何文档来支持该理论。


8
认为这与参数依赖查找有关。我标记了“语言律师”,因为我认为您正在寻找引用语言标准的答案。这是一个很好的第一个问题!这一切都值得。
Bathsheba

它不会进入命名空间A,您可以看到是否允许Bar从中继承另一个结构A。那就没有歧义了。它更像是继承自加都A::FooBar包括的分辨率FooA::Foo。抱歉,我无法真正准确地表达它。
n314159

@Bathsheba您是指用于查找函数名称(或函数模板名称)还是模板中的从属名称的参数类型从属名称查找吗?
curiousguy19年

Answers:


22

每个类均以其成员的名义注入其名称。所以你可以命名A::Foo::Foo。这称为注入的类名。

[类]

2在看到类名之后,立即将一个类名插入到声明该类名的范围中。类名也被插入到类本身的作用域中。这称为注入类名称。为了进行访问检查,将注入的类名视为公共成员名。

[basic.lookup]

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

因为参数类型的非限定名称查找始于类的范围Bar,所以它将继续进入其基类的范围以说明那里的任何成员。它将找到A::Foo::Foo一个类型名称。

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

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

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

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


5
@TedLyngmo-ADL与函数调用一起发生,与这些特定段落无关。
StoryTeller-Unslander Monica

冲木,我在读书,不确定。谢谢!
Ted Lyngmo

3
这会导致非常有趣,struct Bar:: A::Foo::Foo::Foo::Foo::Foo {}; 但是在某些情况下会A::Foo::Foo指定构造函数,因此您无法继续添加所需的数量Foo。这是类似(但具有完全不同的机制)的事实,你可以调用一个函数f是这样的:(************f)()
AProgrammer19年

@AProgrammer-的确如此。并且可以构造更多有趣的示例
StoryTeller-Unslander Monica

这个答案肯定解释了“什么”。可以添加“为什么”吗?如上,该规则的目的是什么?它可以改善或实现哪些用例?
davidbak

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;
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.