是否需要定义所有前向声明?
一般来说,我想知道像这样的程序(包含从未定义的类的前向声明)在技术上是否格式良好?
class X;
int main() {}
这样的模式是否
// lib.h
#pragma once
struct X {
private:
friend class F;
};
更具体地说,我想知道如果 lib.h
属于不包含类 F
定义的共享库,那么编写 安全,也不依赖于另一个共享库。
使用头文件的人是否有可能最终引用符号 F
,这可能会在加载共享库时导致链接器错误?
In general, I'm wondering if a program like this, containing a forward-declaration of a class that is never defined, is technically well-formed?
class X;
int main() {}
More specifically, I'm wondering if having a pattern like this
// lib.h
#pragma once
struct X {
private:
friend class F;
};
is safe to write if lib.h
belongs to a shared library that does not contain a definition of the class F
, nor does it depend on another shared library that does.
Is it possible that someone using the header file ends up with a reference to symbol F
that may cause a linker error when loading the shared library?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据标准[basic.odr.def]:
关键部分是odr-used,它由代码中可能使用该函数的所有其他位置决定。如果它没有在任何(可能评估的)表达式中命名,则它不会被 odr 使用,也不需要有定义。
更远:
声明函数不需要定义它。调用它、获取其地址或任何其他需要知道函数位置的表达式(获取其地址或调用它)都需要该函数存在,否则链接器将无法链接这些用途到定义。如果没有用途,则不存在对这些符号的依赖性。
同样,对于类,同样的推理也适用。再次,从标准来看:
[示例:以下完整的翻译单元格式良好,
即使它从未定义 X:
— 结束示例]
为了完整性,标准给出的类类型 T 需要完整的原因是:
static_cast
According to the standard [basic.odr.def]:
The key part is odr-used, which is determined by all the other places in code that may make use of the function. If it is not named in any (potentially evaluated) expression, it is not odr-used and does not need to have a definition.
Further:
Declaring function does not require it to be defined. Calling it, taking its address, or any other expression that needs to know the location of the function (to take its address or make a call to it) requires that the function exist, or the linker won't be able to link those uses to the definitions. If there are no uses, there is no dependency on those symbols.
Similarly, for classes, the same kind of reasoning applies. Again, from the standard:
[Example: The following complete translation unit is well-formed,
even though it never defines X:
— end example]
And for completeness, the reasons the standard gives for when a class type T is required to be complete:
static_cast
是的,代码格式良好。
您没有以需要
X
完整的方式使用X
。仅当您尝试创建不完整类型的对象、使用成员或任何需要定义的内容时,才会出现编译器错误。
不完整的类型很好,它们只是……不完整。通常,类型所需的只是声明,而定义并不重要。
作为一个示例,考虑标记类型,这是一种模板类型,其模板参数仅用于创建与模板不同的类型:
标记
tagA
和tagB
不需要定义。它们仅用作标签,以区分A
和B
。A
和B
基本上是相同的类型,但标签使它们成为不同的类型。Yes the code is well-formed.
You are not using
X
in a way that requiresX
to be complete.Only if you try to create an object, use a member, or anything that requires the definition, of an incomplete type there will be a compiler error.
Incomplete types are fine, they are just not ... complete. Often all you need of a type is a declaration while the definition doesn't really matter.
As an example consider a tagged type, a templated type whose template argument is only present to create different types from the template:
The tags
tagA
andtagB
do not need a definition. They are only used as tags, to distinguishA
andB
.A
andB
are basically the same type, but the tag makes them different types.