【问题标题】:inline function and class and header file内联函数和类和头文件
【发布时间】:2013-04-07 17:44:30
【问题描述】:
  1. 头文件中定义的函数会自动内联吗?
  2. 如果我在一个类中声明一个函数并在外部使用关键字 inline 给出定义,这个函数会是内联的吗?如果是,为什么这不违反内联函数应在声明时赋予主体的法律?

【问题讨论】:

  • @JBentley - 但是,该答案错误地应用了 ODR。
  • @JBentley - 我收回了。 ODR 处理不同翻译单元以及同一翻译单元中的多个定义。现在我必须撤回我在下面的 cmets 中所说的所有内容。 :-(

标签: c++ class inline one-definition-rule


【解决方案1】:

在类定义中定义的任何函数都是内联的。任何标记为inline 的函数也是内联的。

class C {
    int f() { return 3; } // inline
    int g();
    int h();
}


inline int C::g() { return 4; } // inline
int C::h() { return 5; } // not inline

如果所有这些代码都在一个标头中,并且该标头用于多个翻译单元,您将收到一条投诉,称C::h 有多个定义。 C::fC::g 没问题,因为它们是内联的。这就是inline 如今的主要作用:允许在多个地方定义相同的函数(只要定义“相同”)。

【讨论】:

    【解决方案2】:

    头文件中定义的函数会自动内联吗?

    不,您应该手动将在类主体之外定义的任何函数内联。否则,您很可能会收到 ODR 违规(如果在多个翻译单元中包含标头)。

    ISO C++11

    3.2 一个定义规则

    1:任何翻译单元不得包含一个以上的任何变量、函数、类类型、枚举类型或模板的定义。

    [...]

    4:每个程序都应包含该程序中odr 使用的每个非内联函数或变量的一个定义;无需诊断。定义可以显式出现在程序中,可以在标准或用户定义库中找到,或者(在适当时)隐式定义(参见 12.1、12.4 和 12.8)。内联函数应在使用它的每个翻译单元中定义。


    如果我在一个类中声明一个函数并在外面使用关键字 inline 给出定义,这个函数会是内联的吗?如果是,为什么这不违反内联函数应该在声明时赋予主体的法律?

    有几种方法可以内联成员函数:

    首先,根据7.1.2/3:

    在类定义中定义的函数是内联函数。 inline 说明符不应出现在块作用域函数声明中。90 如果在友元声明中使用 inline 说明符,则该声明应为定义,或者该函数应先前已被内联声明。

    struct First
    {
        void first(){}
    };
    

    第二、第三和第四,根据 9.3/3:

    内联成员函数(无论是静态的还是非静态的)也可以在其类定义之外定义只要它在类定义中的声明或在类定义之外的定义将函数声明为内联。 [注意:命名空间范围内的类的成员函数具有外部链接。本地类 (9.8) 的成员函数没有链接。见 3.5。 ——尾注]

    struct STF
    {
        void second();
        inline void third();
        inline void fourth();
    };
    
    inline void STF::second(){}
    void STF::third(){}
    inline void STF::fourth(){}
    

    【讨论】:

    • 问题只是同一事物的多个定义。这与 ODR 无关,后者要求当允许多个定义时,它们必须相同。此外,它不仅仅是非成员函数,而是任何未在类定义中定义的函数。
    • @PeteBecker。 “这与 ODR 无关”——真的吗?您能否详细说明 ODR 与“问题只是同一事物的多个定义”无关?
    • 真的。如果您有两个同名的非内联定义,那就是错误;一直是,永远都是。在这个问题的上下文中,ODR 说,当您有两个相同函数的定义都标记为inline 时,它们必须是“相同的”。所以inline int f() { return 3; } inline int f() { return 4; } 违反了 ODR。 int f() { return 3; } int f() { return 3; } 只是对同一事物的两个定义,以及一个错误。
    • 没有。如果您在两个不同的翻译单元中有int f() { return 3; } 的定义,这是一个错误。与 ODR 无关。您还省略了 95% 的定义 ODR 的文本。那段之后有很多东西。
    • 你说得对:我把它看得太狭隘了。大多数时候,“ODR 问题”用于指代不同的类或内联函数的定义;但它是关于何时以及如何在多个地方定义相同名称的各种规则的总称。
    【解决方案3】:

    inline 是一个“提示”,只要编译器不必遵守它。它可以使您没有标记为内联的内容内联,并且不必内联您标记为内联的内容。

    我的意思是你不应该依赖它。许多人建议您甚至不要使用它,因为它具有误导性。大多数现代编译器完全忽略它。

    唯一的实际用途是允许您将静态实现放入标题中。这是否是一件好事是有争议的。

    【讨论】:

    • 谢谢!这是否意味着当头文件中发生定义时,即使没有使用关键字 inline,也会自动给出提示?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多