C++20“寻址限制”有什么用?

Ben*_*uch 7 c++ std c++20

根据 cppreference.com,C++20 引入了标准库函数的“寻址限制” :

寻址限制

如果 C++ 程序显式或隐式尝试形成指针、引用(对于自由函数和静态成员函数)或指向成员的指针(对于非静态成员函数),则该程序的行为是未指定的(可能是格式错误的)标准库函数或标准库函数模板的实例,除非它被指定为可寻址函数(见下文)。

以下代码在 C++17 中定义良好,但会导致未指定的行为,并且自 C++20 起可能无法编译:

#include <cmath>
#include <memory>
 
int main()
{
    auto fptr0 = &std::betaf; // by unary operator&
    auto fptr1 = std::addressof(std::betal); // by std::addressof
    auto fptr2 = std::riemann_zetaf; // by function-to-pointer implicit conversion
    auto &fref = std::riemann_zetal; // forming a reference
}
Run Code Online (Sandbox Code Playgroud)

为什么要引入这个?

特别是在语言的向后兼容性方面,这似乎是一个破坏了许多现有代码的更改。这带来了什么好处,值得进行如此重大的改变?

Mar*_*low 7

它从来都不是“明确定义的”,它只是碰巧适用于您/某些/大多数实现。(这里CppReference是错误的)

标准的库部分的介绍中隐藏着对实现者必须提供的内容的描述。对于(例如)std:: riemann_zetal,需要的是有一个可以使用函数调用语法调用的“事物”,它采用单个float参数,并返回可以转换为float.

所以,这是一个完全合法的实现:

template <typename FP>
FP ZETA(FP f, int flags = 0) { /* code here */ } 

#define riemann_zetaf(x)  ZETA<float>(x, 23)
Run Code Online (Sandbox Code Playgroud)

但是,你不能获取地址,riemann_zetaf因为不存在这样的野兽。

请注意,即使没有宏,您也不能保证addressof(riemann_zetal)会返回一个只接受一个参数的函数。您拥有的唯一保证是您可以使用一个参数来调用它。

如果您需要可以获取地址的内容,请自行定义:

float riemann_zetal (float x) { return std::riemann_zetal(x); }
Run Code Online (Sandbox Code Playgroud)

然后取它的地址。

  • @MarshallClow `C17 7.1.4 使用库函数 /1` 允许 C 标准库函数为宏。我在 C++ 标准中找不到 C++ 标准库实体的相同措辞。 (3认同)
  • 我认为宏参数使讨论偏离了要点,即:标准库可以有默认参数、模板或添加额外的重载等,从而导致地址不明确、不是匹配的函数或不可用首先。无法保证它永远有效,并且依赖它在现实中只是“可能没问题”,但不符合规范。遵守规范可以保护您免受未来库更改的影响。 (2认同)