c++ - 有没有办法将“内联”关键字的两个含义分开(ODR 放松与功能代码内联)
问题描述
我想我完全理解inline
C++ 中关键字的含义。具体来说,它意味着两个半相关的事情:
- 声明的函数的 ODR 规则放宽了
inline
。因此,您可以在多个 TU 中定义相同的功能符号,而在链接它们时不会出错。这允许在标题中定义函数。 - 这是对编译器的建议,它应该用函数的已编译代码的副本代替函数的调用,而不是
call
指向函数符号地址的指令。
我可以理解,这两个含义必然是在一个方向上相关的:2 必须暗示 1。#2 要求函数定义对调用函数的所有 TU 都可用。因此,函数定义必须存在于多个 TU 中。因此需要放宽 ODR 以避免链接器错误。
但我的问题是关于另一个方向 - 为什么语言设计成 1 必须暗示 2?
在某些情况下和某些设计决策中,希望能够放宽函数的 ODR,而不建议编译器实际上应该内联函数代码,这似乎是合理的。如果我有一个想要通过头文件分发的函数,我必须将其标记为inline
放宽 ODR (#1)。但是现在我被迫进入#2,即使我有具体的知识,就性能而言,该函数不是内联的好候选者。
我的理解是,模板函数不存在这种不需要的含义。模板函数的 ODR 会自动放宽(必须如此)。这使我inline
只能将其用作性能建议。
我知道在头文件中分发函数,而不是静态库,可能是个坏主意。但作为一名程序员,我有可能知道自己在做什么,并且我想要这种灵活性。我对模板函数具有这种灵活性,那么为什么不使用非模板函数呢?
或者是否有一种可移植的方式来放松 ODR 而不建议内联函数?例如,在 MSVC 上,您可以这样做:
__declspec(noinline) inline void Foo() {}
这里inline
放宽了 ODR,但__declspec(noinline)
要求编译器实际上不内联调用。但是__declspec(noinline)
不便携。
谢谢!
解决方案
但是
__declspec(noinline)
不便携。
您可以使用平台检测宏使其可移植到具有类似属性的所有实现。GCC 和 Clang 有__attribute__((noinline))
.
另一种方法是根本不在乎。编译器仍然可以选择忽略它认为已经隐含的偏好。如果内联扩展很昂贵(因为函数很大),智能编译器应该避免扩展它。
推荐阅读
- microsoft-graph-api - 是否有任何 REST API 可以为 Microsoft Teams 中的用户启用/禁用录制?
- javascript - React Native ios报错无效uiscrollviewindicatorstyle应该是黑白默认
- linux - Papi_avail 没有可用的事件 - 未知的 libpfm4 相关错误
- javascript - 访问表调用写入和读取
- javascript - Chart.update 不是函数类型错误
- javascript - 需要帮助访问 Firestore 子集合?
- bash - 用于输出包含搜索字符串的行的 Bash 函数,带有警告
- haskell - 模式匹配元组不是完全惰性的吗?
- material-ui - 在 firebase 上运行 yarn upgrade,现在我收到 Material-UI/Alert 错误
- php - How does a Laravel model get a "required" data? New column, adding another column's data