解释和第一个例子
举个例子
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 规则。