2

我对 C++ 标准第 3.2 节 [basic-def-odr] 项目符号点 6(即 -3.2.6)几乎没有疑问。

指定了几个条件来判断一个类是否可以多次定义,每个定义都在单独的翻译单元中。

我无法在此项目符号中找到以下强调部分的示例:

在 D 的每个定义中,对应的名称,根据 [basic.lookup] 查找,应指在 D 的定义中定义的实体,或在重载解析 ([over.match]) 后引用相同的实体,并且在匹配部分模板特化 ([temp.over]) 之后,除了如果对象在 D 的所有定义中具有相同的文字类型,并且该对象是使用常量表达式 ([expr.const]) 进行初始化,并且该对象未被使用,并且该对象在 D 的所有定义中具有相同的值。

任何人都可以举一个例子,其中“应引用在 D 的定义中定义的实体”结果是错误的,并且将多个定义视为错误......

如果可以提供示例来解释同一部分中的以下项目符号,那将更有帮助。

在 D 的每个定义中,(隐式或显式)函数调用使用的默认参数被视为其标记序列存在于 D 的定义中;也就是说,默认参数受上述三个要求的约束(并且,如果默认参数具有带有默认参数的子表达式,则此要求以递归方式适用

提前致谢

4

1 回答 1

3

解释和第一个例子

举个例子

class Z { char c; };

class X {
public: 
    using Y = Z;  // Z refers to an entity outside definition of D
    Y f();        // Y refers to an entity within definition of D
};

措辞

应指在 D 的定义中定义的实体, 应指同一实体

意思是:

  • 要么您引用在 X 中定义的实体(Y在 的声明中的示例f()),
  • 或者您引用不在 X 中的实体(Z用于定义的示例Y),但它应该引用您定义 X的所有编译单元中的同一实体。

实际上,这种复杂的措辞只是意味着如果您在不同的编译单元中定义相同的类(具有相同的标记序列,如您引用的上面的破折号所要求的那样),它应该具有相同的含义。目的是允许在头文件中定义一个类,并在多个 cpp 文件中包含相同的头文件。

你怎么能打破这个规则?

只需对相同的 X 类使用相同的包含,但使用 Z 类的不同版本。这不符合 odr 要求:

文件 Xh:

class X {
public: 
    using Y = Z;  // Z refers to an entity outside definition of D
    Y f();        // Y refers to an entity within definition of D
private: 
    Y yes; 
};

文件 Z1.h:

class Z { char c; };

文件 Z2.h:

class Z { int c; char d; };  ///  OOPS !! same class, not same token 

文件 a.cpp

#include "Z1.h"
#include "X.h"   // X is defined with one meaning for Z 

void myfunc (X a) { ... } 

文件 b.cpp

#include "Z2.h"
#include "X.h"   // ouch X is defined but using another layout for Z !!
extern void myfunc (X a); 
int main() { X oops;  myfunc(oops); }   // ==> what will happen here ?  

根据您的 C++ 实现,这可能会以多种方式失败:链接器错误(因为名称修改算法可能会失败)、内存/堆栈损坏(因为 myfunc 期望堆栈上具有一定大小的对象,但 main 正在推送一个对象堆栈上的不同大小)等...

编辑:默认值

在类函数中,您可以定义参数的默认值。您的附加报价只是说适用于 D 项目的规则也适用于用作默认参数的表达式。例子:

const int I_HATE_GLOBALS=sizeof(int)*3; 

struct T {
   void show (size_t a=I_HATE_GLOBALS); 
};     

在此示例中,如果I_HATE_GLOBALS始终以相同的方式定义,则可以在多个翻译单元中出现相同的 T 定义。但是,如果您在多个 cpp 文件中使用相同的 T 定义,但如果您使用包含和条件编译的魔力来获得 I_HATE_GLOBAL不同的定义,那么您将违反 ODR 规则。

于 2016-04-13T20:09:58.630 回答