ODR(Used,Useable)

文中绝大部分内容出自个人翻译,从这里,其中个人翻译将在之后发布.

关于C++ODR

了解ODR必须知道的:

  • 声明域(Declarative region)作用域(scope)
  • 什么是 潜在求值(potentially evaluated)
  • 什么是 named by an expression
  • 什么是 odr-used
  • 什么是 odr-useable
  • 什么是 odr

Delarative region 与 scope

翻译过来实际上,前者就是声明域,后者是作用域</br>
对于Delarative region,官方对其的描述是:</br>
代码中引入一个名字的部分;Delarative region是该名字依然有效的最大区域,即可以通过非限定名称来引用同一个实体</br>
scope:</br>
scope是值在代码中可能不是连续的部分里一个名字是有效的,为了判断一个声明作用域,最简单的方法就是判断其 潜在的作用域 potential scope,通常,潜在作用域是和作用域是相同的,但是,如果潜在作用域内存在了另一个同名的声明,那么此时潜在作用域中,里面的声明域是不包含外面的声明域的.</br>
[注记:简单来说,一个名字的Delarative region通常是包含了这个名字所存在的整个区域,potential scope则是自这个名字开始起,一直到这个名字彻底不可见为止,scope则是在potential scope的基础上,如果在其基础上存在了内层的代码块且用了同一个名字进行声明的,则自那个内层名字被引入起直到其potential scope结束的这一块是排除在这个名字的scope之外的]</br>
[Note:一个声明声明了一个名字并将这个名字引入相应的作用域内,但是friend,详细类型指定符,using指令则会打破这个规则]</br>
在一个声明域的一组均制定了同一非限定名字的声明,他们应该引用一个实体,或者均引用函数和函数模板,或者当一个声明是非typedef的名字的类名或枚举名字,其他的同样的名字则是引用同一变量,非静态数据成员,或枚举项,或者均为函数或函数模板,则这个类或枚举明就被隐藏</br>
[注意:一个名称空间和类模板名字必须在一个声明域内唯一]</br>
intervening declarative region 这个则是表明,在一个declarative region和其的一点间的region,这个region恒等于这个declarative region</br>

Potentially evaluated

潜在求值说白了,就是将对一个id表达式进行求值</br>
其通常包含了一切含有一个id,并且这个id指向的是一个变量实体</br>
在标准中有如下描述:</br>
一个表达式e的潜在求值集合是:</br>
当e为一个id表达式时,集合为e本身</br>
当e为一个数组下标表达式e1[e2]时,其集合为数组下表操作数(e1,e2)的集合</br>
当e为一个类成员访问表达式,则集合为对象表达式的集合</br>
当e为一个成员指针表达式,且第二个操作数是一个常量表达式时,集合就对象表达式的集合</br>
当e的形式是(e)时,集合为e的集合</br>
当e是泛左值条件表达式(三目)时,集合是第二和第三个操作数的集合</br>
当e是一个逗号表达式时,集合是右操作数的集合</br>
否则集合为空</br>

Named By an Expression

这一条主要是针对函数的</br>
概括上说,就是直接对函数(名字)的操作,除了非显式使用限定符的纯虚函数或是成员指针的形式调用.</br>
标准中有如下描述:</br>
一个函数的名称出现在一个表达式中并且其是名称查找的唯一的结果或是一系列重载函数中被选中(经过重载决议后的唯一确定调用的)的那个则就叫被那个表达式命名,除非他是一个没有显示使用限定名称的纯虚函数或是一个使用成员指针的形式</br>
[注记:这条规定涵盖了对函数取址,使用一个名字调用函数,运算符重载,用户定义的类型转换,new或placement new以及非默认的初始化.一个一个类类型的构造函数选择赋值或移动一个对象是被认为是named by an expression的即使其调用可能被实现忽略]</br>
一个类的分配(new)和一个解分配(delete)函数被一个new-expression named,就像在expr.newexpr.deleteclass.free说的一样</br>

odr-used

odr-used实际上就是指一个变量在潜在求值的集合或函数Named By an Expression</br>

标准中有如下描述:</br>

  • 一个变量x出现在了一个潜在求值表达式ex中则说明这个表达式被odr-used,除非</br>这个表达式对这个变量进行了左值到右值使其成为一个常量表达式并且期间没有调用任何非trivial的函数,并且</br>如果x是一个对象,ex是表达式e中潜在求值集合的元素,则要求表达式被应用于左值向右值的转换,或者e是一个弃值表达式</br>
  • 一个结构化绑定是odr-used,只要其出现在了潜在求值表达式中</br>
  • *this被odr-used,只要this出现在了潜在求值表达式中(包括在非静态成员函数中的隐式使用)</br>
  • 一个虚函数只要不为纯虚函数则它就被odr-used,一个函数被odr-used只要他被一个潜在求值表达式named by,一个类的非placement new 或一个解分配函数被其构造函数odr-used.一个类的非placement 解分配函数被其析构函数odr-used或被当前定义的虚析构函数查找到.</br>
  • 一个类的赋值操作符重载函数被odr-used在其他类中隐式定义的复制赋值运算符或移动赋值运算符函数,就像[class.copy.assign]中说的.一个类的构造函数被odr-used就像[dcl.init]中说的,一个类的析构函数只要被潜在调用则其就被odr-used</br>

odr-useable

这条规定主要是针对一个在某声明域中的局部变量的</br>

标准中有如下描述:一个本地变量是odr-useable的,只要满足下列条件

  • 这个局部变量不是*this,或在一个封闭类内或在一个非lambda函数形参域中并且,如果最内层作用域是一个函数参数作用域则这个函数是非静态成员函数.
  • 对于每一个intervening declarative region在实体被引入的点和*this被认为随着最内层封闭类或非lambda函数引入的定义作用域则:
    • intervening declarative region是一个块作用域
    • 或intervening declarative region是lambda函数参数作用域并且这个实体被用名字捕获或默认捕获
  • 如果一个局部变量在其非odr-useable的地方被odr-used该程序是ill-formed

odr

odr实际上就是单一定义原则,这条规定说明存在某些实体在整个程序中唯一,则该唯一的要求是什么</br></br>
对于inline来说,每个程序应该完全包含一个inline函数,变量的实体,只要其在非弃值语句外被odr-used,并且每个odr-used之的翻译单元必须存在定义.</br></br>
对于一个类来说,只要当前翻译单元需要一个该类的完整类型,那么这个类必须在这个翻译单元内定义,对于要求一个类T的完整类型的情况,标准有如下定义:</br></br>

存在T的对象的定义</br>
一个T的非静态成员函数被声明</br>
T作为分配函数的类型或数组元素的类型</br>
一个泛左值引用了一个类型T并且对这个引用进行了一个左值到右值的类型转换</br>
一个向T类型的转型</br>
一个有别于cv void*的表达式使用C++的类型转换方式转向T类型的指针</br>
对类型T的对象进行的一个类型成员访问运算符</br>
对类型T使用了typeid或sizeof运算符</br>
返回类型或形参类型为T的函数被定义或调用</br>
以T为基类的类型定义</br>
一个类型为T的左值被赋值(包括复合赋值)</br>
被alignof包围的类型T的表达式</br>
抛出对象类型为T,指向或引用T</br>

对于一个类类型,枚举类型,有外部连接的内联函数内联变量,类模板,非静态函数模板,制约,类模板的静态成员,类模板的成员函数,模板偏特化,以上定义通常应在每个不同的翻译单元中出现,并且需要满足下列要求:</br></br>
对于以上在不同的(多于一个的)翻译空间内定义的实体D有:</br></br>
每一个D的定义都应该有相同的一系列token组成,并且</br></br>
在重载决议和模板偏特化匹配后,在每个D的定义中,相应的名字都应该遵循基本的名称查找原则,并且应该在D的定义范围内指的是同一个实体或应该指向同一实体,除非这个名字指的是:</br></br>

一个非volatile的const对象并且有内部或无链接,如果这个对象:

  • 在所有D的定义中都有相同的字面类型
  • 是由一个常量表达式初始化的
  • 在任何D的定义内都是非odr-used,并且
  • 有所有D的定义内都有同样的值

    是一个有内部或无链接的常量表达式的引用,这类引用在所有D的定义内都指向同一实体

并且
在每个D的定义内,相应的实体应该有同样的语言链接,并且</br></br>
在每个D的定义内,重载运算符,隐式调用的类型转换函数,构造函数,new,delete 运算符重载,都应该指向同一个函数,或者指向D定义的函数的定义,并且</br></br>
在每个D的定义内,显式或隐式的使用默认参数的函数调用,其被视为D定义的序列中的token,因此,默认参数也是服从于本段所有的描述(并且,如果默认参数有一个有默认实参的子表达式,那么以上要求也是递归的被要求检查的),并且</br></br>
如果D有先决条件的调用了了一个函数,或者这个函数包含一个断言或者有一个制约条件,则它是被隐式定义在所有的D的定义都应该使用同样的构建等级和冲突延续模型下,并且</br></br>
如果D是一个有隐式定义的构造函数的类,则它的行为就像这个构造函数在每个其被ord-used的翻译单元中隐式定义,并且这个在每个翻译单元中隐式的定义对于每个D的子对象而言都应该调用同样的(同一个)构造函数</br></br>
如果D是一个模板,并且其在多余一个的翻译单元中被定义,则上述要求应该都应用于模板定义中模板作用域中所有的名字,并且依赖其实例化点的名字,如果D的定义满足所有的特点,那么整个程序的行为就像整个程序中只有一个D的定义一样.[注意:一个实体的声明仍然需要在多翻译单元中出现,并且链接仍然作用域这些声明,特别是在类D中可能导致不同声明有截然不同的类型lambda表达式],如果D的定义不满足上述要求,则程序的行为未定义.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,137评论 6 511
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,824评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,465评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,131评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,140评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,895评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,535评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,435评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,952评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,081评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,210评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,896评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,552评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,089评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,198评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,531评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,209评论 2 357

推荐阅读更多精彩内容