【发布时间】:2011-07-28 22:55:34
【问题描述】:
假设我有这些类型:
struct A {
int a;
};
struct B {
int b;
};
struct C : public A, public B {
int c;
};
C* 指针可以转换为 A* 指针,而无需调整实际地址。但是当C* 被强制转换为B* 时,该值必须改变。我想确保我拥有的两个相关类型可以相互转换而不会改变地址(即没有多重继承,或者基类是派生类的第一个基类)。这可以在运行时检查,例如像这样
assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000);
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000);
这行得通。但是这些信息在编译时是已知的,所以我正在寻找一种方法来对其进行编译时断言。将上述内容转换为静态断言的明显方法(例如,将 assert 替换为 BOOST_STATIC_ASSERT 会给出错误“转换为整数或枚举类型以外的类型不能出现在常量表达式中”使用 g++ 4.2。
可移植性并不太重要。使用 gcc 扩展或 hacky 模板技巧都可以。
更新:发现之前问过几乎一样的问题:C++, statically detect base classes with differing addresses?。使用offsetof() 也是唯一有用的建议。
【问题讨论】:
-
不想成为吹毛求疵的人,但既然确切的内存布局是一个实现细节......你为什么会对这个感兴趣?
-
我很确定 Boost/lambda 库包含这方面的内容。我必须查一下,但 Alexandrescu 和 Vandervoorde 已经发表了该领域的几乎所有技巧
-
我对@Matthieu M. 提出的问题真的很感兴趣:在什么情况下演员可以是微不足道的? (即,如果它不是微不足道的,那么成本很可能可以忽略不计:向派生指针添加一个常量,如果条件没有正确完成,您将在尝试调试看起来像是损坏的内存时遇到真正的痛苦)跨度>
-
说来话长。这是一个事件系统,我想使用类型擦除来减少模板膨胀。例如。我想将 f(T*) 类型的函数指针(对于许多不同的 T)视为 f(void*),以将它们存储在通用结构中。进一步的细节很复杂。关键是有很多重复的模板化代码实际上是相同的,因为演员表是微不足道的(在大多数情况下,我正在处理,实际上是这样)。我试图避免重复生成的相同代码,但让编译器检查我没有搞砸:)
-
@DS,您可能希望检查链接器的设置。一些链接器能够检测和合并相同的函数,因此即使您的编译器生成了许多重复项,您正在进行的合并它们的工作可能是计算机可以为您完成的工作.
标签: c++ pointers casting static-assert