我有一个具有内联成员的类,但后来我决定要从头文件中删除实现,因此我将函数的成员主体移到 cpp 文件中。起初我只是将内联签名留在头文件中(我马虎),程序无法正确链接。然后我修复了我的标题,当然一切正常。
但内联不是完全可选的吗?
在代码中:
第一:
//Class.h
class MyClass
{
void inline foo()
{}
};
下一个改为(不会链接):
//Class.h
class MyClass
{
void inline foo();
};
//Class.cpp
void MyClass::foo()
{}
然后到(会正常工作):
//Class.h
class MyClass
{
void foo();
};
//Class.cpp
void MyClass::foo()
{}
我认为 inline 是可选的,并想象我可能会因为我的草率而受到警告,但没想到会出现链接错误。在这种情况下,编译器应该做的正确/标准的事情是什么,根据标准,我应该得到我的错误吗?
最佳答案
确实,有一个定义规则说,内联函数必须在它使用的每个翻译单元中定义。血淋淋的细节如下。第一个3.2/3:
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:
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 链接,因此它的任何定义都将引用 same 函数(或者更血腥 - 指向相同的 entity)。
关于我的 claim 的血腥细节。第一个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:
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.
这个“用于链接目的的名称”很有趣:
typedef struct { [...] } the_name;
由于现在您的程序中有同一实体的多个定义,ODR 的另一件事恰好限制了您。 3.2/5 后面是无聊的东西。
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
- each definition of D shall consist of the same sequence of tokens; and
- in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (13.3) and after matching of partial template specialization (14.8.3) [...]
我现在切断了一些不重要的东西。以上是关于内联函数需要记住的两个重要内容。如果您多次定义 extern 内联函数,但确实以不同方式定义它,或者如果您定义它并且其中使用的名称解析为不同的实体,那么您正在执行未定义的行为。
函数必须在使用它的每个 TU 中定义的规则很容易记住。并且它是相同的也很容易记住。但是那个名字解析的东西呢?这里有一些例子。考虑一个静态函数assert_it:
static void assert_it() { [...] }
现在,由于 static 会给它内部链接,当你将它包含到多个翻译单元中时,每个定义都会定义一个不同的实体。这意味着您不允许使用将在程序中多次定义的外部内联函数中的 assert_it:因为发生的情况是内联函数将引用到一个 TU 中名为 assert_it 的实体,但到另一个 TU 中的另一个同名实体。你会发现这都是无聊的理论,编译器可能不会提示,但我发现这个例子特别显示了 ODR 和实体之间的关系。
接下来是再次回到您的特定问题。
以下是相同的东西:
struct A { void f() { } };
struct A { inline void f(); }; void A::f() { } // same TU!
但是这个不同,因为函数是非内联的。您将违反 ODR,因为如果您多次包含 header ,则您对 f 的定义不止一个
struct A { void f(); }; void A::f() { } // evil!
现在如果你把 inline 放在类中 f 的声明上,然后在头文件中省略定义它,那么你就违反了 3.2/3 (和 7.1.2/4 说同样的事情,只是更详细),因为该函数没有在该翻译单元中定义!
请注意,在 C (C99) 中,内联的语义与在 C++ 中不同。如果你创建一个外部内联函数,你应该首先阅读一些好论文(最好是标准),因为这些在 C 中真的很棘手(基本上,任何使用的函数内联定义都需要另一个非内联函数定义TU. C 中的静态内联函数很容易处理。它们的行为与任何其他函数一样,除了具有通常的“内联替换”提示。C 和 C++ 中的静态 inline 仅用作内联-替换提示。由于 static 在任何时候使用它都会创建一个不同的实体(因为内部链接),inline 只会添加内联替换提示 - 不会更多。
关于c++ - C++ 的内联不是完全可选的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/908830/
我打算为ruby脚本创建一个安装程序,但我希望能够确保机器安装了RVM。有没有一种方法可以完全离线安装RVM并且不引人注目(通过不引人注目,就像创建一个可以做所有事情的脚本而不是要求用户向他们的bash_profile或bashrc添加一些东西)我不是要脚本本身,只是一个关于如何走这条路的快速指针(如果可能的话)。我们还研究了这个很有帮助的问题:RVM-isthereawayforsimpleofflineinstall?但有点误导,因为答案只向我们展示了如何离线在RVM中安装ruby。我们需要能够离线安装RVM本身,并查看脚本https://raw.github.com/wayn
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
如果names为nil,则以下中断。我怎样才能让这个map只有在它不是nil时才执行?self.topics=names.split(",").mapdo|n|Topic.where(name:n.strip).first_or_create!end 最佳答案 其他几个选项:选项1(在其上执行map时检查split的结果):names_list=names.try(:split,",")self.topics=names_list.mapdo|n|Topic.where(name:n.strip).first_or_create!e
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
背景here.在上面的链接中,给出了以下示例:classauthor.id)endend除了这种语法对于像我这样的初学者来说很陌生——我一直认为类方法是用defself.my_class_method定义的——我在哪里可以找到关于类的文档RubyonRails中的方法?据我所知,类方法总是在类本身(MyClass.my_class_method)上调用,但如果Rails中的类方法是可链接的,似乎必须进行其他操作在这里!编辑:我想我通过对类方法的语法发表评论有点被骗了。我真的想问Rails如何使类方法可链接—我了解方法链接的工作原理,但不知道Rails如何允许您链接类方法而无需实际返
什么是测试格式验证的最佳方法让我们说一个用户名,使用字母数字的正则表达式,但不是纯数字?我一直在我的模型中使用以下验证validates:username,:format=>{:with=>/^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i}数字用户名(例如“342”)通过了验证,这是我不想要的。 最佳答案 您想“向前看”一封信:/\A(?=.*[a-z])[a-z\d]+\Z/i 关于ruby-on-rails-Rails格式验证——字母数字,但不是纯数字,我们在Sta
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=