[英]c++ compile time assert that BASE is base class of EXTENDED and have same memory address
struct A
{
};
struct B : A
{
virtual ~B() {}
};
template<typename BASE, typename EXTENDED>
void ASSERT_BASE_EXTENDED()
{
static_assert(static_cast<BASE*>((EXTENDED*)256)==(BASE*)256, "error");
}
I'm looking for a way to have a compile time assertion to check if BASE class is a base of EXTENDED, and they have the same memory address.我正在寻找一种方法来进行编译时断言来检查 BASE 类是否是 EXTENDED 的基类,并且它们具有相同的内存地址。
In the above example even though B is based on A, when casted to A it has a different memory address, because the virtual function table pointer is actually the first member of B. But I need a check if A is the first member.在上面的例子中,即使 B 基于 A,当转换为 A 时,它具有不同的内存地址,因为虚函数表指针实际上是 B 的第一个成员。但我需要检查 A 是否是第一个成员。
The above works OK but is not compile-time, because I'm getting an error "error C2131: expression did not evaluate to a constant" when using VS 2017 compiler.以上工作正常,但不是编译时,因为我在使用 VS 2017 编译器时收到错误“错误 C2131:表达式未计算为常量”。
I'm not interested in "std::is_base_of" because that one ignores checking for the same memory address.我对“std::is_base_of”不感兴趣,因为它忽略了对相同内存地址的检查。 Is there another way to do this?
有没有另一种方法可以做到这一点?
Thanks谢谢
Memory addresses are a runtime construct.内存地址是运行时构造。 You cannot check them at compile time because at that point they don't exist.
您不能在编译时检查它们,因为那时它们不存在。 The same is true for the kind of casting you mention.
你提到的那种铸造也是如此。 That happens at runtime entirely.
这完全发生在运行时。 You'll have to replace
static_assert
with a runtime check and error handling, eg an assert()
or an exception.您必须使用运行时检查和错误处理来替换
static_assert
,例如assert()
或异常。
That's for the imo common use case.那是针对 imo 常见用例的。 For hard-coded memory addresses like in your example the problem is the cast of those address-ints to pointers.
对于像您的示例中那样的硬编码内存地址,问题是将这些地址整数转换为指针。 The only valid way to do this is a reinterpret_cast (that's one of the casts the compiler tries for the C-style cast in your example), because the types int and pointer to T are completely unrelated.
执行此操作的唯一有效方法是 reinterpret_cast (这是编译器在您的示例中为 C 样式转换尝试的转换之一),因为类型int和指向 T 的指针完全无关。 But reinterpret_cast is not allowed at compile time.
但是在编译时不允许 reinterpret_cast。
Clang's error message puts it nicely: Clang 的错误信息说得很好:
main.cpp:14:38: note: cast that performs the conversions of a reinterpret_cast is not allowed in a constant expression
static_assert(static_cast<BASE*>((EXTENDED*)256)==(BASE*)256, "error");
^
Limitation: it works only with classes which has constexpr constructors限制:它仅适用于具有 constexpr 构造函数的类
class Base_A
{
size_t a;
};
class Base_B
{
size_t b;
};
class Derived2: public Base_A, public Base_B
{
size_t x;
};
template<class Derived, class Base>
constexpr bool IsSameAddressCast()
{
Derived drv;
Derived* drv_p = &drv;
Base* base_p = drv_p;
void* drv_v = drv_p;
void* base_v = base_p;
return (drv_v==base_v);
};
static_assert(IsSameAddressCast<Derived2, Base_A>(), "different address");
static_assert(IsSameAddressCast<Derived2, Base_B>(), "different address");// this assert will triggers
Another solution suppose you can access some not static member in base class另一个解决方案假设您可以访问基类中的一些非静态成员
class Base_A
{
public:
size_t amember;
};
class Base_B
{
size_t b;
};
class Derived1: public Base_B, public Base_A
{
size_t x;
};
class Derived2: public Base_A, public Base_B
{
size_t x;
};
class Derived3: public Base_B
{
public:
size_t amember;
};
template<class T>
struct Allocator_OffsetOf_ObjData
{
static const size_t value = (size_t)&(((T*)nullptr)->amember);
};
template<class Derived, class Base>
constexpr bool IsSameAddressCast2()
{
static_assert(std::is_base_of<Base, Derived>::value, "not a base class");
return Allocator_OffsetOf_ObjData<Base>::value == Allocator_OffsetOf_ObjData<Derived>::value;
}
static_assert(IsSameAddressCast2<Derived1, Base_A>(), "different base address");// triggers assert
static_assert(IsSameAddressCast2<Derived2, Base_A>(), "different base address");
static_assert(IsSameAddressCast2<Derived3, Base_A>(), "different base address");// triggers assert
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.