inline 说明符

来自cppreference.com
< cpp‎ | language

inline 说明符,在用于函数的 声明说明符序列 时,将函数声明为一个 内联(inline)函数

整个定义都在 class/struct/union 的定义且被附着到全局模块 (C++20 起)的函数是隐式的内联函数,无论它是成员函数还是非成员 friend 函数。

声明有 constexpr 的函数是隐式的内联函数。

弃置的函数是隐式的内联函数:它的(弃置)定义可以在多于一个翻译单元中出现。

(C++11 起)

inline 说明符,在用于具有静态存储期的变量(静态类成员或命名空间作用域变量)的 声明说明符序列 时,将变量声明为内联变量

声明为 constexpr 的静态成员变量(但不是命名空间作用域变量)是隐式的内联变量。

(C++17 起)

解释

内联函数内联变量 (C++17 起)具有下列性质:

  1. 内联函数或变量 (C++17 起)的定义必须在访问它的翻译单元中可达(不一定要在访问点前)。
  2. 外部链接的 inline 函数或变量 (C++17 起)(例如不声明为 static)拥有下列额外属性:
  1. 内联函数或变量 (C++17 起)在程序中可以有多于一次定义,只要每个定义都出现在不同翻译单元中(对于非静态的内联函数和变量 (C++17 起))且所有定义等同即可。例如,内联函数或内联变量 (C++17 起)可以在被多个源文件所 #include 的头文件中定义。
  2. 它必须在每个翻译单元中都被声明为 inline
  3. 它在每个翻译单元中都拥有相同的地址。

在内联函数中,

  • 所有函数定义中的函数局部静态对象在所有翻译单元间共享(它们都指代相同的在某一个翻译单元中定义的对象)
  • 所有函数定义中所定义的类型同样在所有翻译单元中相同。

命名空间作用域的内联 const 变量默认具有外部链接(这点与非内联非 volatile 的有 const 限定的变量不同)

(C++17 起)

inline 关键词的本意是作为给优化器的指示器,以指示优先采用函数的内联替换而非进行函数调用,即并不执行将控制转移到函数体内的函数调用 CPU 指令,而是代之以执行函数体的一份副本而无需生成调用。这会避免函数调用的开销(传递实参及返回结果),但它可能导致更大的可执行文件,因为函数体必须被复制多次。

因为关键词 inline 的含义是非强制的,编译器拥有对任何未标记为 inline 的函数使用内联替换的自由,和对任何标记为 inline 的函数生成函数调用的自由。这些优化选择不改变上述关于多个定义和共享静态变量的规则。

由于关键词 inline 对于函数的含义已经变为“容许多次定义”而不是“优先内联”,因此这个含义也扩展到了变量。

(C++17 起)

注解

如果具有外部链接的内联函数或变量 (C++17 起)在不同翻译单元中的定义不同,那么行为未定义。

inline 说明符不能用于块作用域内(函数内部)的函数或变量 (C++17 起)声明。

inline 说明符不能重声明在翻译单元中已定义为非内联的函数或变量 (C++17 起)

隐式生成的成员函数和任何在它的首条声明中声明为预置的成员函数,与任何其他在类定义内定义的函数一样是内联的。

如果一个内联函数在不同翻译单元中被声明,那么它的默认实参的积累集合必须在每个翻译单元的末尾相同。

在 C 中,内联函数不必在每个翻译单元声明为 inline(最多一个可以是非 inlineextern inline),函数定义不必相同(但如果程序依赖于调用的是哪个函数则行为未指明),且函数局部的静态变量在同一函数的不同定义间不同。

关于内联静态成员的额外规则见静态数据成员

内联变量消除了将 C++ 代码打包为只有头文件的库的主要障碍。

(C++17 起)

示例

头文件 "example.h":

#ifndef EXAMPLE_H
#define EXAMPLE_H
 
#include <atomic>
 
// 定义将被多个源文件包含的函数必须是 inline 的
inline int sum(int a, int b) 
{
    return a + b;
}
 
// 拥有外部链接的包含于多个源文件的变量必须是 inline 的
inline std::atomic<int> counter(0);
 
#endif

源文件 #1:

#include "example.h"
 
int a()
{
    ++counter;
    return sum(1, 2);
}

源文件 #2:

#include "example.h"
 
int a() // 这个函数与源文件 #1 中的不是同一个函数
{
    ++counter;
    return sum(3, 4);
}
 
int b()
{
    ++counter;
    return sum(5, 6);
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 281 C++98 友元函数声明可以在函数本身不是内联函数的情况下使用 inline 说明符 禁止在此类情况下使用
CWG 317 C++98 即使一个函数已经有非内联定义,在(相同翻译单元内)
该定义之后依然可以声明该函数为内联函数
此时程序非良构
CWG 765 C++98 在内联函数内定义的类型在不同的翻译单元可能不同 这些类型在所有翻译单元一致
CWG 1823 C++98 内联函数的所有定义中的字符串字面量在所有翻译单元间共享 由于一致性与实现移除该要求

参阅