C++编译时断言,BASE是基类的延伸,具有相同的内存地址

C++编译时断言,BASE是基类的延伸,具有相同的内存地址

问题描述:

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

我正在寻找一种方式来有一个编译时断言检查,如果基类的延伸的基础,他们有相同的内存地址。C++编译时断言,BASE是基类的延伸,具有相同的内存地址

在上面的例子中,即使B是基于A的,当被转换为A时它具有不同的存储器地址,因为虚拟函数表指针实际上是B的第一个成员。但是我需要检查如果A是第一名成员。

上述工作正常,但不是编译时,因为我得到一个错误:使用VS 2017年编译器时,“错误C2131表达式的结果不是一个常量”。

我不感兴趣“的std :: is_base_of”,因为这一个忽略检查相同的内存地址。 有没有另一种方法来做到这一点?

谢谢

+0

你想使用[_CRTP_(https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)和'static_cast'? – user0042

+0

CRTP是一个有趣的概念,但目标是不要修改现有的类,只调整ASSERT_BASE_EXTENDED函数。 – Esenthel

内存地址是一个运行时构造。你不能在编译时检查它们,因为那时它们不存在。你提到的那种铸造也是如此。完全在运行时发生。您必须使用运行时检查和错误处理来替换static_assert,例如一个assert()或一个例外。

这对国际海事组织共同使用的情况。对于你的例子中的硬编码内存地址,问题是这些地址插入指针。要做到这一点的唯一有效的办法就是reinterpret_cast的(这是编译器试图为C样式转换在你的榜样铸件中的一个),因为该类型INT指针到T完全无关。但是reinterpret_cast在编译时是不允许的。

锵的错误消息所言很好:

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"); 
            ^
+0

我不同意你的看法。如果你再次检查我的代码,你会看到我正在创建一个指向一个256的常量内存地址的对象。另外我使用了static_cast,它与dynamic_cast不同,它可以通过已知的编译器值对内存偏移进行调整。没有什么能够阻止编译器在编译时评估整个行,但它不会。这些基本上是在编译时对已知常量的算术运算。 – Esenthel

+0

我凭直觉将这些硬编码地址用于简化问题。对于这种情况,实际问题是演员。查看更新后的答案。 – besc

+0

IMO无论编译器能够优化(预先计算) - 他们应该。如果他们愿意,那么它会解决我的问题。 – Esenthel