簡體   English   中英

c ++編譯時斷言BASE是EXTENDED的基類並且具有相同的內存地址

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM