C/C++编程:单一定义规则ODR(不理解)
ODR规则
- 任何变量、函数、类类型、枚举类型、概念 (C++20 起)或模板,在每个翻译单元中都只允许有一个定义(其中部分可以有多个声明,但是只允许有一个定义)
- 在整个程序中,被ODR式使用非
inline
函数或变量只允许有且仅有一个定义。。编译器不要求对这条规则的违反进行诊断,但违法它的行为是未定义的 - 对于
inline函数
或inline 变量 (C++17 起)
来说,在ODR式使用了它的每个翻译单元中都需要一个定义 - 在以需要将类作为完整类型的方式给予的每个翻译单元中,要求有且仅有该类的一个定义。
以下各种实体:类类型、枚举类型、inline函数、inline变量 (C++17 起)、模板实体(模板和模板成员,但不完全模板特化),在程序中可以出现多个定义,只要满足下列条件
- 每个定义出现在不同翻译单元
- 定义不附着到具名模块(C++20 起)
- 每个定义都由相同的记号序列构成(典型情况下都是在同一个头文件中)
- 每个定义内进行名字查找(在重载决议后)都找到相同实体,除了
- 具有内部连接或无连接的常量可以指代不同对象,只要不ORD使用它们的基类序列被唯一标志(C++11起)
- 不在默认实参或默认模板实参 (C++20 起)中的 lambda 表达式由定义它们的记号序列被唯一标识
(C++11 起)
- 被重载的运算符(包括转换、分配和解分配函数),在各个定义中都代表相同的函数(除非它们代表的是在这个定义中所定义的函数)
- 它们具有相同的语言连接(比如包含文件时并未处于某个 extern “C” 块之中)
- 以上三条规则同样适用于各个定义中的所有默认实参
- 如果该定义是模板定义、则所有这些要求一同适用于定义点大的各个名字和实例化的各个待决名
若满足了所有这些要求,则程序的行为如同在整个程序中只有一个定义。否则程序非良构,不要求诊断。
注意:
- 在C中,类型没有全程序范围的ODR、而同一变量的extern声明甚至可以在不同的翻译单元中具有不同的类型,只要它们是兼容的类型即可。
- 在 C++ 中,用于同一个类型的声明的源代码记号必须与上述相同:如果一个 .cpp 文件定义了 struct S { int x; }; 而另一个 .cpp 文件定义了 struct S { int y; };,则将它们连接到一起的程序的行为未定义。
- 无名命名空间通常被用于解决这种问题。
ODR使用
非正式地说:
- 一个对象在其值被读取(除非它是编译时常量)或写入,或其地址被取,或者被引用绑定时,这个对象被 ODR 使用。
- 使用“所引用的对象在编译期未知”的引用时,这个引用被 ODR 使用。
- 一个函数在被调用或其地址被取时,被 ODR 使用。
如果一个对象、引用或函数被 ODR 使用,则其定义必须存在于程序中的某处;否则常为连接时错误。
struct S {static const int x = 0; // 静态数据成员// 如果 ODR 使用它,就需要一个类外的定义
};
const int& f(const int& r);int n = b ? (1, S::x) // S::x 此处并未 ODR 使用: f(S::x); // S::x 此处被 ODR 使用:需要一个定义
C/C++编程:单一定义规则ODR(不理解)相关推荐
- c语言程序中unit怎么定义,c ++中的一个定义规则(One definition rule in c++)
c ++中的一个定义规则(One definition rule in c++) 根据c ++标准: 任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义. //--translat ...
- 总结一下F#中运算符的定义规则
F#允许开发人员定义或重载各类运算符,合理利用这一规则可以让编程变得方便,让代码更容易阅读.例如,在使用F#的MailboxProcessor的时候,我会习惯于定义一个运算符来代替显式的Post操作: ...
- C语言初学者编程规范—命名规则
原文地址:C语言初学者编程规范-命名规则 C是一门朴素的语言,你使用的命名也应该这样.与Modula-2和Pascal程序员不同,C程序员不使用诸如"ThisVariableIsATempo ...
- 从λ演算到函数式编程聊闭包(2):彻底理解JavaScript闭包规则
闭包是很多语言都具备的特性,上篇<从抽象代数漫游函数式编程(1):闭包概念再Java/PHP/JS中的定义> 闭包的特性 闭包有三个特性: 函数嵌套函数 函数内部可以引用外部的参数和变量 ...
- iptables 定义规则
iptables定义规则的方式大概是这种格式: iptables [-t table] COMMAND chain CRETIRIA -j ACTION -t 表名:指定要操作的表 COMMAND:定 ...
- java定义一个类计算圆的半径,C++编程:定义一个圆类要求属性为半径,操作为计算圆的周长和面积...,java编程:定义一个圆类,属性为半径,方法为对输入的半径计...
导航:网站首页 > C++编程:定义一个圆类要求属性为半径,操作为计算圆的周长和面积...,java编程:定义一个圆类,属性为半径,方法为对输入的半径计 C++编程:定义一个圆类要求属性为半径, ...
- Python变量名的定义规则与定义方式
变量名的定义规则 1.变量名只能是 字母.数字或者下划线的任意组合 2.变量名的第一个字符不能是数字 3.一下关键字不能声明为变量名 常用定义方式 驼峰法 AgeOfOld=56 NumberOfSt ...
- 宏定义编程软件_什么是计算机编程? 定义软件开发。
宏定义编程软件 My five year old son, Ramy, approached me one day while I was working from home and asked, & ...
- 【编程实践】什么是计算机编程?定义软件开发。What is Computer Programming? Defining Software Development.
目录 什么是计算机编程?定义软件开发.What is Computer Programming? Defining Software Development. What is Computer Pro ...
最新文章
- Spring Cloud第三篇:服务消费者Feign
- Nature科学报告:根据大脑思维意图来生成对应匹配的图像
- EasyUI中搜索框的简单使用
- python解包操作_Python编程使用*解包和itertools.product()求笛卡尔积的方法
- 搜索推荐炼丹笔记:融合GNN、图谱、多模态的推荐
- 微信小程序【腾讯云开发】创建并上线小程序项目(涉及-数据库操作)
- 自开发Web应用和SAP Customer Data Cloud Identity服务的集成
- java B2B2C springmvc mybatis电子商务平台源码-消息队列之RocketMQ
- 【CodeForces - 764A】Taymyr is calling you (找规律,水题)
- linux 内核4.12,Linux Kernel 4.12 发布,最新的稳定版内核
- 基于springboot+vue的学生选课系统(前后端分离)
- [golang 易犯错误] golang 局部变量初始化:=的陷阱
- 关于开发工程师的绩效考核
- Android开发-仿网易云音乐播放器样式设计与实现
- C语言--函数-统计单词个数
- JS高级程序设计精简版(第五章:引用类型)附思维导图
- 拼多多微信登陆服务器请求失败,拼多多客服网页无法登陆/卡死,怎么办?
- 网络协议(5) 详解 TCPIP 协议(完结)
- carsim与simulink联合仿真-ABS(制动防抱死系统) 入门——详细步骤
- 【MATLAB教程案例26】图像特征点提取算法matlab仿真与分析——sift,surf,kaze,corner,BRISK等
热门文章
- 浅谈数字经济新技术间的关系——云计算、物联网、大数据、区块链、人工智能、元宇宙
- Java开发入门练习题
- Redis 交集并集差集
- java greenplum_java实现greenplum数据库导入实践
- 【博弈论基础与几大经典模型】古诺模型、斯塔克尔伯格模型Stackelberg Game、价格领导模型、Bertrand模型、Sweezy模型
- C# winform 动物识别专家系统
- ebay注册流程_个人卖家如何注册eBay?2019 eBay个人账号开店注册流程
- 电信移动流量卡为什么首月免月租?联通卡却不免头铁呢?
- 【板栗糖GIS】CC—ContextCapture10.20的安装教程
- 中医养生APP小程序开发 了解传统文化传承医学经典