简体   繁体   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");
}

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.

相关问题 在编译时检查 class 是否在 C++ 中有任何基础 class - Check if the class has any base class in C++ in compile time C++ - 检测是编译时的第一个基类 - C++ - detect is first base class at compile time C ++:使用类型名作为基础的模板类中的函数调用编译时错误 - C++ : Function call Compile-Time Error from a Template Class using Typename as Base 在C ++中,为什么编译器在编译时不理解基类对象指向哪个对象? - in C++, why compiler does not understand which object is pointed by base class object at compile time? 如何创建一个在编译时仅继承两个基类之一的 C++ 类? - How to make a C++ class that inherits from only one of two base classes at compile time? C ++将私有成员从派生类访问到另一个派生类(两者都具有相同的基类) - C++ Access private member from a derived class to another derived class (both have the same base class) 在编译时查找基类 - Finding base class at compile time 在C ++中,如何仅对一个变量具有内存,同时在基类和派生类中定义 - In C++ how to have memory only for one variable define both in base & derived class C++ 中的编译时 Base64 解码 - Compile-Time Base64 Decoding in C++ C ++:为什么要编译? (将本参考移交给基类) - C++: Why does this compile? (Handing this-Reference to base class)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM