Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 做c++;内联友元函数导致名称隐藏在名称空间之间?_C++ - Fatal编程技术网

C++ 做c++;内联友元函数导致名称隐藏在名称空间之间?

C++ 做c++;内联友元函数导致名称隐藏在名称空间之间?,c++,C++,考虑以下代码: namespace Foo1 { void add( int ) {} void subtract( int ) {} } namespace Foo2 { class Bar { public: friend void add( Bar ) {} }; void subtract( Bar ) {} void xxx() { int i = 0; using namespace F

考虑以下代码:

namespace Foo1 {
void add( int ) {}
void subtract( int ) {}
}

namespace Foo2 {


    class Bar {
    public:
        friend void add( Bar ) {}
    };

    void subtract( Bar ) {}

    void xxx() {
        int i = 0;
        using namespace Foo1;
        add( i );  // Is this an error or not?
        subtract( i ); // This is an error due to name hiding
    }
}
Foo2::xxx()
中,我使用使用名称空间来访问
Foo1::add
Foo1::subtract
。调用subtract显然是一个错误,因为
Foo2::subtract
隐藏名称。但是
Foo2::add
不应该在
Foo2
中真正可见,因为它只能 可以使用ADL找到,它不应该隐藏
Foo1::add
。我的理解正确吗

我已经在MSVC和gcc的多个版本上尝试了上述代码。前者一直是如此
拒绝了添加(i)呼叫,但我不清楚错误消息。后者一直接受这一点。以下哪项(如果有的话)是正确的?

我认为GCC就在这里

[namespace.memdef](强调我的)

如果非本地类中的友元声明首先声明 类、函数、类模板或函数模板朋友是 最内层封闭命名空间的成员朋友宣言 本身不会使名称对非限定查找可见 ([basic.lookup.unqual])或限定查找([basic.lookup.qual])。 [ 注意:如果 在命名空间范围中提供了匹配声明(在之前或之后) 课程结束后(给予友谊)。 — 尾注 ] 如果 调用友元函数或函数模板时,可以找到其名称 按名称查找,该查找考虑来自名称空间和 和函数参数类型关联的类 ([basic.lookup.argdep])

这样,不合格的<代码>添加(i)< /> >本身不应该找到<代码>添加(bar)< /代码>的声明,这意味着查找应该继续,并考虑使用指令所带来的名称。并且由于该参数不是类类型,所以ADL是不可能的。<代码>不应隐藏<代码>添加(int)< /> > .< /p> ,如已经指出的(C++ 20标准,7.7.1.2命名空间成员定义)

3如果非本地类中的友元声明首先声明一个类, 函数、类模板或函数模板100朋友是 最内层封闭命名空间的成员

因此,此友元函数
add
是名称空间Foo2的成员。但是,在名称空间
Foo2
中出现相应的函数声明之前,它在名称空间
Foo2
中是不可见的。只有通过依赖于参数的查找才能找到它

namespace Foo2 {

    class Bar {
    public:
        friend void add( Bar ) {}
    };
    //..
如果在函数
xxx
之前写入,则命名空间
Foo1
中的名称
add
将被隐藏

namespace Foo2 {

    class Bar {
    public:
        friend void add( Bar ) {}
    };

    void add( Bar );
    //...
void xxx() {
    int i = 0;
    using namespace Foo1;
    add( i );  // Is this an error or not?
    subtract( i ); // This is an error due to name hiding
}
也就是说,如果友元函数
add
将在封闭的命名空间中重新声明

在函数内
xxx

namespace Foo2 {

    class Bar {
    public:
        friend void add( Bar ) {}
    };

    void add( Bar );
    //...
void xxx() {
    int i = 0;
    using namespace Foo1;
    add( i );  // Is this an error or not?
    subtract( i ); // This is an error due to name hiding
}
编译器按以下顺序考虑名称substract。首先它查看封闭的名称空间,即名称空间
Foo2
。此名称空间具有声明的名称
substract
。因此搜索过程停止。重载函数
void substract(int)未找到
,因为由于using指令,它被视为全局命名空间的成员。全局命名空间是包含using指令中指定的命名空间的命名空间和包含using指令的命名空间的命名空间

您可以考虑以下方式(由于使用DouTibe)

您可以使用using声明代替using指令,使命名空间Foo1中的两个函数在函数xxx中可见

比如说

void xxx() {
    int i = 0;
    using Foo1::subtract, Foo1::add;
    add( i );  // Is this an error or not?
    subtract( i ); // This is an error due to name hiding
}

@彼得-朋友不是班上的成员,而是朋友them@Peterfriend函数实际上不属于该类,即使它们是在类主体中定义的。@Peter A friend不是其类的成员。肯定没有
Foo2::Bar::add
add
定义了
Foo2
的成员,但是不会自动声明为可见的
Foo2
声明,因此只能通过依赖参数的查找找到它。
subtract(i)
是一个错误,因为名称隐藏。请查看@j_kubik Oh我没有注意。我更新了我的答案。