我可以获取标准库中定义的函数的地址吗?

2024-04-25

考虑以下代码:

#include <cctype>
#include <functional>
#include <iostream>

int main()
{
    std::invoke(std::boolalpha, std::cout); // #1

    using ctype_func = int(*)(int);
    char c = std::invoke(static_cast<ctype_func>(std::tolower), 'A'); // #2
    std::cout << c << "\n";
}

在这里,两个调用std::invoke已标记以供将来参考。 预期输出是:

a

C++20 能保证预期的输出吗?

(注意:有两个函数称为tolower— 一中<cctype>另一个在<locale>。引入显式强制转换来选择所需的重载。)


简短回答

No.

解释

[命名空间.std] http://eel.is/c++draft/namespace.std#6 says:

Let F表示标准库函数([全局函数] http://eel.is/c++draft/global.functions)、标准库静态成员函数或标准库函数模板的实例化。Unless F被指定为可寻址函数,如果 C++ 程序显式或隐式尝试形成指向的指针,则该程序的行为是未指定的(可能是格式错误的)F. [Note:形成此类指针的可能方法包括应用一元&操作员 ([expr.unary.op] http://eel.is/c++draft/expr.unary.op), addressof ([专门.地址] http://eel.is/c++draft/specialized.addressof),或函数到指针的标准转换 ([转换功能] http://eel.is/c++draft/conv.func). — end note] 此外,如果 C++ 程序尝试形成对以下内容的引用,则其行为是未指定的(可能格式错误):F或者如果它尝试形成一个指向成员的指针,指定标准库非静态成员函数([成员函数] http://eel.is/c++draft/member.functions) 或标准库成员函数模板的实例化。

考虑到这一点,让我们检查这两个调用std::invoke.

第一次通话

std::invoke(std::boolalpha, std::cout);

在这里,我们试图形成一个指向std::boolalpha。幸运的是,[fmtflags.manip] http://eel.is/c++draft/fmtflags.manip#1拯救世界:

本节中指定的每个函数都是指定的可寻址函数([命名空间.std] http://eel.is/c++draft/namespace.std).

And boolalpha是本节中指定的函数。 因此,该行格式良好,相当于:

std::cout.setf(std::ios_base::boolalpha);

但这是为什么呢?那么,下面的代码是必要的:

std::cout << std::boolalpha;

第二次通话

std::cout << std::invoke(static_cast<ctype_func>(std::tolower), 'A') << "\n";

很遗憾,[cctype.syn] http://eel.is/c++draft/cctype.syn#1 says:

标题的内容和含义<cctype>与C标准库头相同<ctype.h>.

无处是tolower显式指定一个可寻址函数。

因此,这个 C++ 程序的行为是未指定的(可能是格式错误的),因为它试图形成一个指向tolower,未指定为可寻址函数。

结论

无法保证预期输出。 事实上,甚至不能保证代码能够编译。


这也适用于成员函数。 [namespace.std] 没有明确提及这一点,但从 [member.functions] 可以看出,如果 C++ 程序尝试获取声明的成员函数的地址,则其行为是未指定的(可能是格式错误的)在C++标准库中。每[成员.函数]/2 http://eel.is/c++draft/member.functions#2:

对于 C++ 标准库中描述的非虚拟成员函数,实现可以声明一组不同的成员函数签名,前提是对从本文档中描述的声明集中选择重载的成员函数的任何调用行为如下如果选择了该过载。 [Note:例如,实现可以添加具有默认值的参数,或者用具有等效行为的两个或多个成员函数替换具有默认参数的成员函数,或者为成员函数名称添加附加签名。 —end note ]

And [expr.unary.op]/6 http://eel.is/c++draft/expr.unary.op#6:

重载函数的地址只能在唯一确定引用重载函数的版本的上下文中获取(请参阅[over.over])。 [Note:由于上下文可以确定操作数是静态还是非静态成员函数,因此上下文还可以影响表达式的类型是“指向函数的指针”还是“指向成员函数的指针”。 —end note ]

因此,如果程序显式或隐式尝试形成指向 C++ 库中的成员函数的指针,则该程序的行为是未指定的(可能是格式错误的)。

(感谢您的comment https://stackoverflow.com/questions/55687044/can-i-take-the-address-of-a-function-defined-in-standard-library/55687045#comment98781473_55687045指出这一点!)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我可以获取标准库中定义的函数的地址吗? 的相关文章

  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable

随机推荐