Constexpr 是否意味着内联?

考虑以下内联函数:

// Inline specifier version
#include<iostream>
#include<cstdlib>


inline int f(const int x);


inline int f(const int x)
{
return 2*x;
}


int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}

以及同等版本的 Constexpr:

// Constexpr specifier version
#include<iostream>
#include<cstdlib>


constexpr int f(const int x);


constexpr int f(const int x)
{
return 2*x;
}


int main(int argc, char* argv[])
{
return f(std::atoi(argv[1]));
}

我的问题是: 如果一个非常量参数被传递给一个 constexpr函数,那么编译器会尝试使用 inline函数,就好像在它的声明中放入了 inline参数一样,constexpr参数是否意味着 inline参数?

C + + 11标准能保证这一点吗?

45934 次浏览

是的([ dcl.Constexpr ] ,C + + 11标准中的7.1.5/2) : “ Constexpr 函数和 Constexpr 构造函数是隐式内联的(7.1.2)。”

但是请注意,inline说明符对编译器是否可能内联展开函数的影响很小(如果有的话)。但是,它确实会影响一个定义规则,从这个角度来看,编译器需要遵循与 inline函数相同的 constexpr函数规则。

我还要补充的是,尽管 constexpr意味着 inline,但 C + + 11中 constexpr函数的规则要求它们足够简单,以至于它们通常是内联扩展的好候选者(主要的例外是那些递归的函数)。然而,从那时起,规则变得越来越松散,因此 constexpr可以应用于更大、更复杂的函数。

对于非静态变量(C + + 17个内联变量) ,constexpr并不意味着 inline

虽然 constexpr确实暗示函数使用 inline,但考虑到 C + + 17内联变量,它对非静态变量没有这种影响。

例如,如果您使用我发布在: 内联变量是如何工作的?的最小示例并删除 inline,只留下 constexpr,那么变量将获得多个地址,这是内联变量避免的主要问题。

但是,constexpr静态变量是隐式内联的。

最小的例子,constexpr意味着函数的 inline

正如在: https://stackoverflow.com/a/14391320/895245中提到的,inline的主要作用不是内联,而是允许一个函数的多个定义,标准报价在: C + + 头文件如何包含实现?

我们可以通过下面的例子来观察:

Main.cpp

#include <cassert>


#include "notmain.hpp"


int main() {
assert(shared_func() == notmain_func());
}

不是 Main.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP


inline int shared_func() { return 42; }
int notmain_func();


#endif

不是 main.cpp

#include "notmain.hpp"


int notmain_func() {
return shared_func();
}

编译并运行:

g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'notmain.o' 'notmain.cpp'
g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.o' 'main.cpp'
g++ -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.out' notmain.o main.o
./main.out

如果我们从 shared_func中删除 inline,链接将会失败:

multiple definition of `shared_func()'

因为头文件包含在多个 .cpp文件中。

但是如果我们用 constexpr代替 inline,那么它又可以工作了,因为 constexpr也意味着 inline

GCC 通过在 ELF 对象文件中将符号标记为弱来实现这一点: C + + 头文件如何包含实现?

在 GCC 8.3.0中测试。