为什么有内联函数声明而不是内联函数调用?

时间:2018-01-24 12:59:07

标签: c++

C ++(和其他各种语言)支持内联函数。如果我想要一个内联函数,我必须在声明中使用inline关键字。对我而言,这种接缝非常不直观:为什么我在调用函数时不能只使用inline?示例:

void foo(){...}
inline foo();

而不是

inline void foo(...){...}
foo();

这将允许我仅在特定位置内联函数而无需复制函数。此外,每个功能都可以内联,这将使机制更加灵活。有没有理由说这不支持?

3 个答案:

答案 0 :(得分:4)

前言:

内联函数内联的行为,即内联扩展是一种优化,其中函数调用被重复的指令集替换

声明内联函数是向链接器声明该函数的处理方式与非内联函数不同。具体而言,内联函数的单定义规则是不同的。允许在多个翻译单元中定义内联函数(并且实际上需要在函数被使用的所有翻译单元中定义)。这与非内联函数不同,非内联函数必须在一个转换单元中定义。 inline关键字可用于声明内联函数。

虽然内联声明的命名方式与内联优化类似,虽然前者可以间接影响后者是否可行,但这两个概念是分开的。

现在,回答。

  

如果我想要内联函数,我必须在声明中使用inline关键字。

您不必使用inline关键字。如果函数在同一个转换单元中定义,则编译器可以内联对非内联函数的调用。即使这不是要求所有翻译单元的链接时优化器。

示例:

// a.cpp
void foo(){}        // a non-inline function
inline void qux(){} // an inline function
void bar(){
    foo(); // this call to a non-inline function can be expanded inline
           // because the function is defined in the same TU
}

// b.cpp
void foo(); // the non-inline function must not be defined
            // in multiple translation units
inline void qux(){} // the inline function can and must be defined
                    // in both translation units
void xeb(){
    foo(); // this call to a non-inline function can not be expanded inline by
           // the compiler because the function is not defined in the same TU
           // the call can be expanded by a linker
    qux(); // this call can be expanded by the compiler
           // because the function is defined in the same TU
}

也就是说,链接时优化并不总是一个选项,并且函数调用确实发生在翻译单元之间,因此在某些情况下,内联定义确实是必要的,以允许内联扩展。

一个迂腐点:一个函数可以在没有inline关键字的情况下内联声明(如果它是一个成员函数)。

  

为什么我在调用函数时只能使用内联?

语言中没有这样的语法。

请注意,该函数仍然必须在同一个转换单元中定义,否则编译器无法对其进行内联扩展。因此,如果您希望在多个翻译单元中进行内联扩展,则仍需要将该函数声明为内联。

我怀疑没有强制内联扩展的语法的原因可能与为什么没有办法选择if语句的哪个分支是"默认"可能对性能产生边际影响的分支(推理只是我在两种情况下的猜测):人类在优化方面非常糟糕。我认为没有技术原因可以解释为什么不能引入这样的语言特征。但我不希望这样的功能非常有用。

答案 1 :(得分:3)

在C ++中inline 意味着调用应该内联。这意味着允许定义在多个翻译单元中发生,而通常只允许一个定义。

由于头文件通常包含在C ++程序的许多翻译单元中,因此头文件中的任何函数定义都将以多个翻译单元结束。因此,为了实现这一目标,您需要inline这些定义的关键字。它仍然与内联有关,因为在这种情况下(定义在标题中),定义在包含标题的所有调用站点都可用,允许编译器内联它,因为它知道完整定义。如果标题中只有声明可用,则只能在链接期间进行内联(使用'链接时优化'即LTO)。

答案 2 :(得分:1)

简短但甜蜜的回答:"内联"没有做过以往的事情。现在,这意味着链接器应该忽略来自不同编译单元的多个定义,只需选择一个并继续使用它。编译器可以随意使用。大多数或所有现代编译器都忽略"内联"。

额外事实:在最新最好的C ++中,您可以将变量声明为内联。