内联与 constexpr?
使用新的 C++11 标准,什么时候应该使用 inline
关键字而不是 constexpr
关键字? constexpr
关键字是否提供了对 inline
的额外优化,还是仅仅断言必须在编译时计算?
为什么在某些调用不恒定的情况下,constexpr
可以在 GCC 上工作,例如在非 constexpr
上调用 foo(x)
多变的?这是 GCC 中的错误还是它实际上是标准的一部分?
With the new C++11 standard, when should I use the inline
keyword over the constexpr
keyword? Does the constexpr
keyword offer any additional optimization over inline
, or does it merely assert that things must be computed at compile-time?
Why does constexpr
work on the GCC in some cases where the call is not constant, such as calling foo(x)
on a non-constexpr
variable? Is this a bug in the GCC or is it actually part of the standard?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
断言某些东西可以在编译时计算是一种非常强大的优化。
内联仅通过将函数体复制/粘贴到调用站点来删除函数调用。函数体仍然需要执行,您只需节省函数调用的开销。
但是,如果您在编译时评估相同的代码,则它在运行时是免费。
但
inline
和constexpr
都不是主要关于优化的。inline
的主要目的是抑制one-definition-rule,以便可以在头文件中定义函数(这对模板很有用,顺便说一句,也使内联优化更容易)和
constexpr
之所以存在,是因为它在元编程中很有用,顺便说一句,它可以通过将更多计算移至编译时来帮助编译器更好地优化代码。Asserting that something can be computed at compile-time is a pretty strong kind of optimization.
Inlining merely removes a function call, by copy/pasting the function body into the call site. The function body still has to be executed, you just save the overhead of a function call.
But if you make the same code be evaluated at compile-time, it is free at runtime.
But neither
inline
norconstexpr
are primarily about optimization.inline
's main purpose is to suppress the one-definition-rule, so that functions can be defined in headers (which is useful for templates, and incidentally, also makes the inlining optimization easier)And
constexpr
is there because it is useful in metaprogramming, and incidentally, it may help the compiler better optimize the code, by moving more computations to compile-time.引用维基百科:
如果函数超短,则将其标记为内联。如果编译时需要结果,则将函数标记为 constexpr。 (模板参数或数组大小)。我相信如果需要的话,一个功能可以兼而有之。
因此,GCC 在这一点上并没有错。
To quote wikipedia:
Mark functions inline if they are super short. Mark functions as constexpr if the results are required at compile time. (Template parameters or array sizes). I believe a function can be both if needed.
So, GCC is not incorrect in this.
虽然
inline
告诉编译器“此函数在此翻译单元中的某个位置使用,并且对其他目标文件不公开”,但编译器很可能会将函数体插入到调用者中。constexpr
函数对编译器说“该函数没有副作用,并且不依赖于参数本身以外的前提条件”。constexpr
变量只是说“这个变量不会改变,它的数据可以包含到代码中。”。但是,如果您在静态或非静态函数中定义 constexpr 变量,则会有所不同,例如。如果 constexpr 数组是非静态的,gcc 只是将带有硬编码 mov 指令的数据移动到堆栈上,而 static constexpr 只是将数据存储在.text
部分。不带 capture 分配给变量的 Lambda 表达式可以是 constexpr,而不是带 capture,因为如果不带 capture,它们不需要内存来保存捕获,并且它们的工作方式就像带有重载
operator()
的空类(但它们甚至可以使用简单的一元加号将其转换为普通函数指针:+[]{}
)。While
inline
says to the compiler "This function is used somewhere in this translation unit and is not public to other object files", it is likely that the compiler inserts the body of the function into the caller.constexpr
functions say to the compiler "This function has no side effects and does not depend on preconditions other than the parameter itsself."constexpr
variables just say "This variable does not change and its data can be included into the code.". However it makes a difference if you define a constexpr variable in a function static or nonstatic, eg. if aconstexpr
array is nonstatic, gcc just moves the data with hardcodedmov
-instructions onto the stack, whilestatic constexpr
just stores the data in the.text
-section.Lambda expressions without capture assigned to a variable can be constexpr other than with capture, because without they need no memory to save the capture and they work like an empty class with overloaded
operator()
(but they can even be casted to plain function pointers with a simple unary plus:+[]{}
).