3.2 - [basic.def.odr] - 【基本.定义.ODR】

原创 2004年11月02日 13:21:00
请不要转载本文;请不要以任何形式重新出版,发布本文;请在下载本文 24 小时内将其删除;禁止将本文用于商业目的。

3 Basic concepts [basic]

3.2 One definition rule [basic.def.odr]


3 基本概念 【基本】

3.2 唯一定义原则 【基本.定义.ODR】


No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.




An expression is potentially evaluated unless either it is the operand of the sizeof operator (5.3.3), or it is the operand of the typeid operator and does not designate an lvalue of polymorphic class type (5.2.8). An object or non-overloaded function is used if its name appears in a potentially-evaluated expression. A virtual member function is used if it is not pure. An overloaded function is used if it is selected by overload resolution where referred to from a potentially-evaluated expression. [Note: this covers calls to named functions (5.2.2), operator overloading (clause 13), user-defined conversions (12.3.2), allocation function for placement new (5.3.4), as well as non-default initialization (8.5). A copy constructor is used even if the call is actually elided by the implementation. ] An allocation or deallocation function for a class is used by a new expression appearing in a potentially-evaluated expression as specified in 5.3.4 and 12.5. A deallocation function for a class is used by a delete expression appearing in a potentially-evaluated expression as specified in 5.3.5 and 12.5. A copy-assignment function for a class is used by an implicitly-defined copy-assignment function for another class as specified in 12.8. A default constructor for a class is used by default initialization as specified in 8.5. A constructor for a class is used as specified in 8.5. A destructor for a class is used as specified in 12.4.


表达式被有效求值,除非它是 sizeof 运算符(5.3.3)的操作数,或者是 typeid 运算符的操作数,并且指定的不是多态类类型(5.2.8)的左值。在有效求值表达式中出现的对象或非重载函数的名字被应用。如果虚成员函数不是纯的,则其被应用。当重载函数在重载解析中被选择时,其将被应用在有效求值表达式中。【注:这包含对命名函数(5.2.2),运算符重载(章节 13),用户定义转换(12.3.2),放置 new 的存储分配函数(5.3.4),以及非默认初始化(8.5)的调用。对于复制构造函数,即使其调用实际上被实现省略,其仍然被应用。】在有效表达式中,new 表达式应用某类的存储分配或存储释放函数,见 5.3.4 和 12.5。在有效表达式中,delete 表达式应用某类的存储释放函数,见 5.3.5 和 12.5。某类的复制构造函数在另一个类隐式定义的复制构造函数中应用,见 12.8。某类的默认构造函数被默认初始化应用,见 8.5。某类的构造函数按 8.5 中所指定的被应用。某类的析构函数按 12.4 中所指定的被应用。


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 appropriated) 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.


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


Exactly one definition of a class is required in a translation unit if the class is used in a way that requires the class type to be complete. [Example: the following complete translation unit is well-formed, even though it never defines X:

    struct X;                       // declare X as a struct type
    struct X* x1;                   // use X in pointer formation
    X* x2;                          // use X in pointer formation

--end example] [Note: the rules for declarations and expressions describe in which contexts complete class types are required. A class type T must be complete if:

  • an object of type T is defined (3.1, 5.3.4), or
  • an lvalue-to-rvalue conversion is applied to an lvalue referring to an object of type T (4.1), or
  • an expression is converted (either implicitly or explicitly) to type T (clause 4, 5.2.3, 5.2.7, 5.2.9, 5.4), or
  • an expression that is not a null pointer constant, and has type other than void *, is converted to the type pointer to T or reference to T using an implicit conversion (clause 4), a dynamic_cast (5.2.7) or a static_cast (5.2.9), or
  • a class member access operator is applied to an expression of type T (5.2.5), or
  • the typeid operator (5.2.8) or the sizeof operator (5.3.3) is applied to an operand of type T, or
  • a function with a return type or argument type of type T is defined (3.1) or called (5.2.2), or
  • an lvalue of type T is assigned to (5.17). ]


如果某个类以需要其完整类型的方式被应用,则该类需要一个唯一定义。【例:如下的完整翻译单元是良好形式的,即使其没有定义 X

    struct X;                       // 声明 X 为结构体类型
    struct X* x1;                   // 以指针形式应用 X
    X* x2;                          // 以指针形式应用 X

--例完】【注:描述声明和定义在何中语境中需要完整类型的规则。某类型 T 必须完整,当:

  • 类型 T 的一个对象被定义(3.1,5.3.4),或者
  • 左值道右值转换被应用到一个引用类型 T 的一个对象(4.1)的左值,或者
  • 表达式被(隐式或显式)转换为类型 T(章节 4,5.2.3,5.2.7,5.2.9,5.4),或者
  • 不是空指针常量,并且不具有类型 void *,使用隐式转换(章节 4),dynamic_cast(5.2.7)或 static_cast(5.2.9)被转换为类型 T 的指针或 T 的引用,或者
  • 类成员访问运算符被应用到具有类型 T 的表达式上(5.2.5),或者
  • typeid 运算符(5.2.8)或 sizeof 运算符(5.3.3)被应用到一个类型 T 的操作数,或者
  • 返回类型或参数类型为类型 T 的函数被定义(3.1)或被调用(5.2.2),或者
  • 类型 T 的左值被赋值(5.17)。】


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), class template (clause 14), non-static function template (14.5.5), static data member of a class template (, member function template (, or template specialization for which some template parameters are not specified (14.7, 14.5.4) 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), except that a name can refer to a const object with internal or no linkage if the object has the same integral or enumeration type in all definitions of D, and the object is initialized with a constant expression (5.19), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D; and
  • in each definition of D, the overloaded operators referred to, the implicit calls to conversion functions, constructors, operator new functions and operator delete functions, shall refer to the same function, or to a function defined within the definition of D; and
  • in each definition of D, a default argument used by an (implicit or explicit) function call is treated as if its token sequence were present in the definition of D; that is, the default argument is subject to the three requirements described above (and, if the default argument has sub-expressions with default arguments, this requirement applies recursively).25)
  • if D is a class with an implicitly-declared constructor (12.1), it is as if the constructor was implicitly defined in every translation unit where it is used, and the implicit definition in every translation unit shall call the same constructor for a base class member of D. [Example:

        // translation unit 1:
        struct X {
            X(int, int);
        X::X(int = 0) { }
        class D: public X { };
        D d2;                           // X(int) called by D()

        // translation unit 2:
        struct X {
            X(int, int);
        X::X(int = 0, int = 0) { }
        class D: public X { };          // X(int, int) called by D();
                                        // D()'s implicit definition
                                        // violates the ODR

    --end example] If D is a template, and is defined in more than one translation unit, then the last four requirements from the list above shall apply to names from the template's enclosing scope used in the template definition (14.6.3), and also to dependent names at the point of instantiation (14.6.2). If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.


类类型(章节 9),枚举类型(7.2),具有外部连接性的内联函数(7.1.2),类模板(章节 14),非静态函数模板(14.5.5),模板类静态数据成员(,成员函数模板(,或者未指明某些模板参数的模板特化(14.7,14.5.4),可以有多于一个定义,每个定义都出现在程序的不同翻译单元中,并且需要满足如下要求。给定实体命名为 D 在多于一个翻译单元中定义,则
  • 每个 D 的定义应该由相同的标记序列组成;并且
  • 每个 D 的定义,根据 3.4 查找的相应名字,在重载解析(13.3)之后并在模板部分特化(14.8.3)匹配之后,应当指代 D 的定义中定义的实体,或者指代相同实体,除非名字指代具有内部连接性或无连接性的 const 对象,且对象在所有 D 定义中具有相同的整数或枚举类型,同时对象由常量表达式(5.19)初始化,并且对象被使用值(而不是地址),且其值在所有 D 的定义中具有相同的值;并且
  • 每个 D 的定义中,重载运算符,类型转换函数的隐式调用,构造函数,new 运算符函数和 delete 运算符函数应该指代相同函数,或在 D 中定义的函数;并且
  • 每个 D 的定义中的(隐式或显式)函数调用所使用的默认参数,其标记序列被认为同样在 D 的定义中出现;也就是说,默认参数须符合上述三条要求(并且,如果默认参数具有带有默认参数的子表达式,这些要求被递归应用)。25)
  • 如果 D 是带有隐式声明构造函数(12.1)的类,则每个翻译单元都应当隐式定义了这个构造函数,且每个翻译单元的隐式定义应当调用应当调用 D 基类成员的相同构造函数。【例:

        // 翻译单元 1:
        struct X {
            X(int, int);
        X::X(int = 0) { }
        class D: public X { };
        D d2;                           // X(int) D() 调用

        // 翻译单元 2:
        struct X {
            X(int, int);
        X::X(int = 0, int = 0) { }
        class D: public X { };          // X(int, int) D() 调用;
                                        // D() 的隐式定义
                                        // 违反 ODR

    --例完】如果 D 是模板,并在多于一个翻译单元中定义,则以上后四个要求应该被应用到该模板定义(14.6.3)包含的范围中应用名字上,并同样应用到由实例化点(14.6.2)决定的名字上。如果 D 的所有定义满足以上条件,则程序应当表现为仅有一个 D 的定义。如果 D 的任何定义不满足以上条件,则其行为是未定义的。


25) 8.3.6 describes how default argument names are looked up.


25) 8.3.6 节描述怎样进行默认参数查找


PREV [basic.def] | NEXT [basic.scope] 上一页 【基本.定义】 | 下一页 【基本.作用域】


C++ 语言中, 有一个重要的规则就是one de
  • a130737
  • a130737
  • 2014年08月06日 20:06
  • 537


C++ 标准规定“每个程序应该只包含那个程序中用到的每个非内联函数或对象的一个定义”。然而在同一个程序中,一个类、枚举类型、具有内部链接的内联函数和和一 个模板可能有不止一个定义——只要每个定义出现在...
  • digu
  • digu
  • 2007年07月16日 15:10
  • 964


Author:DriverMonkey QQ:196568501 Phone:13410905075 欢迎交流! 用stm32 的配置GPIO 来控制LED 显示状态,可用ODR,BSRR,BRR...
  • peng654321
  • peng654321
  • 2013年12月02日 00:04
  • 8418


C++ 标准规定“每个程序应该只包含那个程序中用到的每个非内联函数或对象的一个定义”。然而在同一个程序中,一个类、枚举类型、具有内部链接的内联函数和和一个模板可能有不止一个定义——只要每个定义出现在一...
  • majcos
  • majcos
  • 2007年01月17日 16:03
  • 826


RCC->APB2ENR|=1    RCC->APB2ENR|=1  GPIOA->CRH&=0XFFFFFFF0; GPIOA->CRH|=0X00000003;//PA8 推挽输出    GPI...
  • lg2lh
  • lg2lh
  • 2012年05月08日 11:21
  • 2195

STM32 通用输入输出端口GPIO BRR、BSRR、ODR寄存器详解

详细页面:http://alanzjl.sinaapp.com/2015/02/gpio_brr_bsrr_odr/ BRR、BSRR、ODR都是用来控制16位针脚的。 其中,BRR和OD...
  • alanzjl
  • alanzjl
  • 2015年02月16日 23:52
  • 5504


第一步 学习GPIO,以按键控制跑马灯为例。 GPIO是相对于stm32来说的,也就是芯片上的IO引脚,如C51上的P0口。但是stm32上的io口拥有更强大的功能,有GPIOA~G,GPIOx共1...
  • gao__kun
  • gao__kun
  • 2014年05月07日 20:17
  • 2775


此系列是为那些读过TC++PL或者具有类似水平的同学准备的,作为系列的第一篇以及有趣的热身,我们来看一个链接问题: D1.cpp #include stdio.h> struct X {...
  • GarfieldEr007
  • GarfieldEr007
  • 2015年12月24日 12:42
  • 644

GPIO口 取反

void GPIO_PinReverse(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) {   /* Check the parameters */   ass...
  • TXF1984
  • TXF1984
  • 2016年03月29日 12:34
  • 995


写这个博客着重缕清自己的思路,对基础的东西有个更好的理解。GPIO中的常用的寄存器 GPIOx_CRH 与GPIOx_CRL : 可以配置GPIO的各种模式,进行初始化。 GPIOx_BSR...
  • wangxuznb
  • wangxuznb
  • 2016年02月14日 22:23
  • 1147
您举报文章:3.2 - [basic.def.odr] - 【基本.定义.ODR】