gpt4 book ai didi

c++ - 为什么友元函数不被视为在没有额外声明的情况下声明它的类的命名空间的成员?

转载 作者:行者123 更新时间:2023-12-03 23:38:42 24 4
gpt4 key购买 nike

假设我们有一个类 foo来自命名空间 space声明一个 friend名为 bar 的函数,稍后定义,如下所示:

namespace space {
struct foo {
friend void bar(foo);
};
}

namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
据我了解, friend void bar(foo);声明 bar成为内部的免费功能 space服用 foo按值(value)。要使用它,我们可以简单地执行以下操作:
auto f = space::foo();
bar(f);
我的理解是我们不必说 space::bar ,因为 ADL 会看到 bar 定义在同一个 namespacefoo (它的参数)并允许我们省略全名限定。尽管如此, 我们被允许对其进行限定 :
auto f = space::foo();
space::bar(f);
哪个工作(并且应该工作)完全相同。
当我引入其他文件时,事情开始变得奇怪。假设我们将类和声明移动到 foo.hpp :
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP

namespace space {
struct foo {
friend void bar(foo);
};
}

#endif //PROJECT_FOO_HPP
以及对 foo.cpp 的定义:
#include "foo.hpp"
#include <iostream>

namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
请注意,我所做的只是将(没有更改任何代码)东西移到了 .hpp - .cpp一对。
然后发生了什么?好吧,假设我们 #include "foo.hpp" ,我们仍然可以这样做:
auto f = space::foo();
bar(f);
但是,我们不再能够做到:
auto f = space::foo();
space::bar(f);
这没有说: error: 'bar' is not a member of 'space' ,这很令人困惑。我相当确定 bar space成员(member),除非我严重误解了一些东西。同样有趣的是,如果我们额外声明(再次!) bar ,但在 foo 之外, 有用。我的意思是如果我们改变 foo.hpp对此:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP

namespace space {
struct foo {
friend void bar(foo);
};

void bar(foo); // the only change!
}

#endif //PROJECT_FOO_HPP
它现在可以工作了。
头文件/实现文件是否有改变预期(至少对我而言)行为的内容?这是为什么?这是一个错误吗?我正在使用 gcc 版本 10.2.0(Rev9,由 MSYS2 项目构建) .

最佳答案

friend 有点微妙声明,虽然它不需要先前声明您的类正在成为 friend 的函数或类,但不会使函数对查找可见,除非通过 ADL。
cppreference :

A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.


这就是为什么您可以找到 bar(f) (执行 ADL)但不是 space::bar(f) (完全限定名称意味着不调用 ADL)。
未找到的调用代码 bar via ADL 需要看到一个声明。在一个文件的版本中,调用代码会看到 space::foo的完整定义.当您将其拆分为 HPP 和 CPP 文件时,调用代码只会看到提供有限可访问性的 friend 声明。
正如您所确定的,如果您想通过普通查找使该函数可见,请声明 foo在“foo.hpp”中:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP

namespace space {
struct foo {
friend void bar(foo);
};

void bar(foo); // Now code that includes foo.hpp will see a declaration for bar
}

#endif //PROJECT_FOO_HPP

关于c++ - 为什么友元函数不被视为在没有额外声明的情况下声明它的类的命名空间的成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67459950/

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