constexpr暗示内联吗?


105

考虑以下内联函数:

// 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符是否在某种意义上暗示说明符,即如果将非恒定参数传递给constexpr函数,则编译器将尝试inline对该函数进行处理,就像说明inline符已放入其声明中一样?

C ++ 11标准是否保证?


5
inline指定者不会执行“ [将编译器尝试内联函数]” 。(或者我可能误解了您的措辞。)
吕克·丹顿

5
inline说明符不再有任何与内联
K-BALLO

2
问题inline是基于与内联直接相关的错误假设。因此,不,constexpr说明者并不意味着该inline说明者,因为意义不存在。
Christian Rau

Answers:


139

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

但是请注意,该inline说明符确实有非常少(如果有的话)的影响在一个编译器是否有可能扩大一个内联函数或没有。但是,它确实会影响一个定义规则,并且从这个角度来看,要求编译器对constexpr函数作为inline函数遵循相同的规则。

我还应该补充一点,无论constexpr暗示如何,C ++ 11中的函数inline规则constexpr要求它们足够简单,以至于它们经常是内联扩展的良好候选者(主要的例外是递归的那些)。但是从那时起,这些规则逐渐变得宽松,因此constexpr可以应用于实质上更大,更复杂的功能。


考虑到常量表达式是在编译时求值的,我想constexpr函数的大多数使用根本不会导致任何代码生成……
Kerrek SB 2014年

11
@KerrekSB constexpr函数可能在编译时评估。但是,C ++ 14标准中充斥着一些标准,这些标准很可能在运行时被调用。例如:std::array<T,N>::at
同名

@Eponymous是,但是只有最简化的形式仍将保留为操作码。例如:绑定检查将在构建时进行评估,因为它们的代码路径为const。但是返回的值将是*(data + offset)
v.oddou

16

constexprinline表示非静态变量(C ++ 17内联变量)

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

例如,如果您以我发布于以下内容的最小示例为例:内联变量如何工作?并删除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());
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

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

#endif

notmain.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

如果我们inline从中删除shared_func,则链接将失败并显示以下内容:

multiple definition of `shared_func()'

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

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

GCC通过在ELF目标文件上将符号标记为弱来实现此目的:C ++头文件如何包含实现?

在GCC 8.3.0中测试。


3
顺便说一句,声明的静态类成员变量constexpr仍然是内联的。cppreference.com:声明的静态成员变量(但不是名称空间范围的变量)constexpr隐式是内联变量。
anton_rh

@anton_rh谢谢,我没有看到该规则,请更新答案。
Ciro Santilli郝海东冠状病六四事件法轮功

这不是open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdf所说的。它说constexpr暗示内联变量。没有提及类作用域的名称空间作用域之间的区别。
v.oddou
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.