不是C ++的内联完全可选吗? [英] Isn't C++'s inline totally optional?

查看:128
本文介绍了不是C ++的内联完全可选吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类有一个内联成员,但我后来决定,我想从标题中删除实现,所以我将函数的成员体移出到一个cpp文件。起初,我只是在头文件中留下了内联签名(马虎),程序无法正确链接。

I have a class that had an inline member, but I later decided that I wanted to remove the implementation from the headers so I moved the members body of the functions out to a cpp file. At first I just left the inlined signature in the header file (sloppy me) and the program failed to link correctly. Then I fixed my header and it all works fine, of course.

但是不是内联完全可选的

在代码中:

首先:

//Class.h
class MyClass
{
   void inline foo()
   {}
};

下一页更改为(不会链接):

Next changed to (won't link):

//Class.h
class MyClass
{
   void inline foo();
};

//Class.cpp
void MyClass::foo()
{}

然后到(将正常工作):

And then to (will work fine):

//Class.h
class MyClass
{
   void foo();
};

//Class.cpp
void MyClass::foo()
{}

我认为内联是可选的,并且想象我可能会得到一个警告,我的错误,但没想到一个链接错误。

I thought inline was optional, and imagined I might get by with a warning for my sloppiness, but didn't expect a linking error. What's the correct/standard thing a compiler should do in this case, did I deserve my error according to the standard?

推荐答案

确实,这是一个编译器在这种情况下应该做的正确/标准的事情。 ,存在这一个定义规则,其指示在其使用的每个翻译单元中必须定义内联函数。 Gory详情如下。第一个 3.2 / 3

Indeed, there is this one definition rule saying that an inline function must be defined in every translation unit it is used. Gory details follow. First 3.2/3:


每个程序应包含每个非 - 在该程序中使用的内联函数或对象;无需诊断。定义可以在程序中显式显示,它可以在标准或用户定义的库中找到,或者(在适当的时候)被隐式定义(见12.1,12.4和12.8)。
在每个使用它的翻译单元中定义一个内联函数。

Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and 12.8). An inline function shall be defined in every translation unit in which it is used.

当然 7.1.2 / 4


内联函数应在每个翻译单元中定义,在每种情况下都应有完全相同的定义(3.2)。 [注意:在内联函数的定义出现在翻译单元中之前,可能会遇到对内联函数的调用。 ]如果具有外部链接的函数在一个翻译单元中声明为内联,则它应在其出现的所有翻译单元中被内联地声明;不需要诊断。具有外部链接的内联函数在所有转换单元中应具有相同的地址。 extern内联函数中的静态局部变量总是引用同一个对象。在外部内联函数中的字符串文字在不同的翻译单元中是相同的对象。

An inline function shall be defined in every translation unit in which it is used and shall have exactly the same definition in every case (3.2). [Note: a call to the inline function may be encountered before its definition appears in the translation unit. ] If a function with external linkage is declared inline in one translation unit, it shall be declared inline in all translation units in which it appears; no diagnostic is required. An inline function with external linkage shall have the same address in all translation units. A static local variable in an extern inline function always refers to the same object. A string literal in an extern inline function is the same object in different translation units.

但是,如果你在类中定义你的函数定义,它隐式声明为 inline 函数。这将允许您在程序中多次包含包含内联函数体的类定义。由于函数有 external 链接,它的任何定义都会引用相同的函数(或更多的gory - 到同一个 entity )。

However, if you define your function within the class definition, it is implicitly declared as inline function. That will allow you to include the class definition containing that inline function body multiple times in your program. Since the function has external linkage, any definition of it will refer to the same function (or more gory - to the same entity).

有关我的索赔的详情。第一个 3.5 / 5

Gory details about my claim. First 3.5/5:


如果类的名称具有外部链接,类范围的类或枚举具有外部链接。

In addition, a member function, static data member, class or enumeration of class scope has external linkage if the name of the class has external linkage.

然后 3.5 / 4


具有命名空间范围的名称具有外部链接。]一个命名类(第9条),或者一个在typedef声明中定义的未命名类,其中该类具有用于链接目的的typedef名。

A name having namespace scope has external linkage if it is the name of [...] a named class (clause 9), or an unnamed class defined in a typedef declaration in which the class has the typedef name for linkage purposes.

这个链接目的的名称是这个有趣的东西:

This "name for linkage purposes" is this fun thing:

typedef struct { [...] } the_name;

现在您的程式中有多个同一个实体的定义另一件事情的ODR恰好限制了你。 3.2 / 5 跟随无聊的东西。

Since now you have multiple definitions of the same entity in your programs, another thing of the ODR happens to restrict you. 3.2/5 follows with boring stuff.


在程序中的类型类型(子句9),枚举类型(7.2),内联函数与外部链接(7.1.2)[...],只要每个定义出现在不同的翻译单元中,以下要求。给定这样的在多个翻译单元中定义的D实体,则

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2) [...] in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then


  • D的每个定义将由相同的令牌序列组成;和

  • 在D的每个定义中,根据3.4查找的对应名称,应指在D的定义内定义的实体,或者在重载分辨后引用同一实体[...]



>我切断了一些不重要的东西。上面是两个重要的一个要记住的内联函数。如果您多次定义extern内联函数,但是定义不同,或者如果定义它和它中使用的名称解析为不同的实体,那么您将执行未定义的行为。

I cut off some unimportant stuff now. The above are the two important one to remember about inline functions. If you define an extern inline function multiple times, but do define it differently, or if you define it and names used within it resolve to different entities, then you are doing undefined behavior.

函数必须在每个使用TU的TU中定义的规则很容易记住。并且它是相同也很容易记住。但是那个名字解析的东西呢?这里有一些例子。考虑一个静态函数 assert_it

The rule that the function has to be defined in every TU in which it is used is easy to remember. And that it is the same is also easy to remember. But what about that name resolution thingy? Here some example. Consider a static function assert_it:

static void assert_it() { [...] }

现在, static 将给它内部链接,当您将它包括到多个翻译单元中时,则每个定义将定义一个不同的实体。这意味着你不能允许在程序中多次定义的extern内联函数中使用 assert_it :因为发生的是内联函数将在一个TU中引用一个名为 assert_it 的实体,而引用另一个TU中同名的另一个实体。你会发现这一切都是无聊的理论,编译器不会抱怨,但我发现这个例子特别显示了ODR和实体之间的关系。

Now, since static will give it internal linkage, when you include it into multiple translation units, then each definition will define a different entity. This means that you are not allowed to use assert_it from an extern inline function that's going to be defined multiple times in the program: Because what happens is that the inline function will refer to one entity called assert_it in one TU, but to another entity of the same name in another TU. You will find that this all is boring theory and compilers won't probably complain, but i found this example in particular shows the relation between the ODR and entities.


以下是再次回到您的特定问题。

What follows is getting back to your particular problem again.

以下是相同的事情:

struct A { void f() { } };
struct A { inline void f(); }; void A::f() { } // same TU!

但是这一个是不同的,因为函数是非内联的。您将违反ODR,因为如果您不止一次地包含标题,则 f 有多个定义

But this one is different, since the function is non-inline. You will violate the ODR, since you have more than one definition of f if you include the header more than once

struct A { void f(); }; void A::f() { } // evil!

现在,如果您在声明中加入 inline f ,然后忽略在标题中定义它,则违反 3.2 / 3 code> 7.1.2 / 4 它说同样的东西,只是更详细),因为函数没有在翻译单元中定义!

Now if you put inline on the declaration of f inside the class, but then omit defining it in the header, then you violate 3.2/3 (and 7.1.2/4 which says the same thing, just more elaborating), since the function isn't defined in that translation unit!

请注意,在C(C99)中,inline与C ++中的语义不同。如果你创建一个外部内联函数,你应该首先阅读一些好的论文(最好是标准),因为那些是真的棘手的C(基本上,任何使用的内联定义的函数将需要另一个非内联函数定义在另一个除了在C和C ++中有通常的inline substitution提示,static inline ,它们的行为类似于任何其他函数因为static将在任何时候使用(因为内部链接)而创建一个不同的实体, inline 将只是添加内联替换提示 - 不多。

Note that in C (C99), inline has different semantics than in C++. If you create an extern inline function, you should first read some good paper (preferably the Standard), since those are really tricky in C (basically, any used inline-definition of a function will need another, non-inline function definition in another TU. static inline functions in C are easy to handle. They behave like any other function, apart of having the usual "inline substitution" hint. static inline in both C and C++ serve only as a inline-substitution hint. Since static will already create a different entity any time it's used (because of internal linkage), inline will just add the inline-substitution hint - not more.

这篇关于不是C ++的内联完全可选吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆