gpt4 book ai didi

c++ - 友元声明的复杂范围规则有什么意义?

转载 作者:可可西里 更新时间:2023-11-01 15:09:55 26 4
gpt4 key购买 nike

我最近发现 friend 声明范围遵循 extremely peculiar rules - 如果您有一个尚未声明的函数或类的 friend 声明(定义),它会在紧邻的命名空间中自动声明(定义),但是非限定和限定查找不可见;但是,友元 函数 声明通过参数相关的查找仍然可见。

struct M {
friend void foo();
friend void bar(M);
};

void baz() {
foo(); // error, unqualified lookup cannot find it
::foo(); // error, qualified lookup cannot find it
bar(M()); // ok, thanks to ADL magic
}

如果您查看标准(请参阅 linked answer),他们会竭尽全力启用这种古怪的行为,在具有复杂规则的合格/非合格查找中添加特定异常(exception)。在我看来,最终结果非常令人困惑1,还有一个要添加到实现中的极端情况。无论是

  • 要求 friend 声明引用现有名称、句点;或
  • 允许他们像现在这样声明东西,但不改变普通名称查找(因此,这些名称变得可见,就像在封闭的命名空间中“正常”声明一样)

似乎更容易实现、指定,最重要的是,更容易理解,我想知道:他们为什么要为这个烂摊子烦恼?他们试图涵盖哪些用例?哪些更简单的规则(尤其是与现有行为最相似的第二条规则)有什么问题?


  1. 例如,在这种特殊情况下

    struct M {
    friend class N;
    };
    N *foo;
    typedef int N;

    你得到 comically schizophrenic error messages

    <source>:4:1: error: 'N' does not name a type
    N *foo;
    ^
    <source>:5:13: error: conflicting declaration 'typedef int N'
    typedef int N;
    ^
    <source>:2:17: note: previous declaration as 'class N'
    friend class N;
    ^

    编译器首先声称不存在 N 之类的东西,但当您尝试提供冲突声明时立即停止装傻。

最佳答案

好吧,要回答这个问题,您必须了解 C++ 的另一个主要特性:模板。

考虑这样一个模板:

template <class T>
struct magic {
friend bool do_magic(T*) { return true; }
};

在这样的代码中使用:

bool do_magic(void*) { return false; }

int main() {
return do_magic((int*)0);
}

退出代码是0还是1

好吧,这取决于 magic 是否曾在任何可观察到的地方用 int 实例化。
至少它会,如果 friend - 仅声明为内联的函数会被普通查找规则找到。
而且您不能通过注入(inject)所有可能的东西来解决这个难题,因为模板可以专门化。

有一段时间是这样,但因“太神奇”和“太不明确”而被取缔。

名称注入(inject)还有其他问题,因为它几乎没有像希望的那样定义明确。参见 N0777: An Alternative to Name Injection from Templates了解更多。

关于c++ - 友元声明的复杂范围规则有什么意义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52122453/

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