[英]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");
}
我正在尋找一種方法來進行編譯時斷言來檢查 BASE 類是否是 EXTENDED 的基類,並且它們具有相同的內存地址。
在上面的例子中,即使 B 基於 A,當轉換為 A 時,它具有不同的內存地址,因為虛函數表指針實際上是 B 的第一個成員。但我需要檢查 A 是否是第一個成員。
以上工作正常,但不是編譯時,因為我在使用 VS 2017 編譯器時收到錯誤“錯誤 C2131:表達式未計算為常量”。
我對“std::is_base_of”不感興趣,因為它忽略了對相同內存地址的檢查。 有沒有另一種方法可以做到這一點?
謝謝
內存地址是運行時構造。 您不能在編譯時檢查它們,因為那時它們不存在。 你提到的那種鑄造也是如此。 這完全發生在運行時。 您必須使用運行時檢查和錯誤處理來替換static_assert
,例如assert()
或異常。
那是針對 imo 常見用例的。 對於像您的示例中那樣的硬編碼內存地址,問題是將這些地址整數轉換為指針。 執行此操作的唯一有效方法是 reinterpret_cast (這是編譯器在您的示例中為 C 樣式轉換嘗試的轉換之一),因為類型int和指向 T 的指針完全無關。 但是在編譯時不允許 reinterpret_cast。
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");
^
限制:它僅適用於具有 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
另一個解決方案假設您可以訪問基類中的一些非靜態成員
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.