为什么将整数文字强制转换为指针值会导致非const表达式?

Lin*_*gxi 7 c++ expression casting const

我正在尝试编写一个结构来计算基类和派生类之间的指针偏移量,作为C++ 03中的常量表达式.代码如下:

template <typename Base, typename Derived, typename Via = Derived>
struct OffsetToBase
{
    static const std::ptrdiff_t val =
        (const char*const)static_cast<Base*const>(static_cast<Via*const>((Derived*const)(1u << 7))) -
        (const char*const)(1u << 7);
};
Run Code Online (Sandbox Code Playgroud)

代码在GCC中编译,但不在clang和VC中编译.clang和VC产生的错误基本上表明初始化器不是一个常量表达式,clang进一步强调了子表达式(Derived*const)(1u << 7).

所以,我的问题是标准对此有何看法?如果初始化程序根据标准不符合常量表达式,那么这背后的原因是什么?

更新: 为了您的兴趣,我发现了以下两个讨论:

"初始化器元素不是常量"错误在Linux GCC中没有任何理由,编译C

关于转换为整数常量表达式(在标准C中)

但我不认为相同的规则适用于C++.

Sam*_*hik 1

根据我对标准的阅读,这不是一个常量表达式:

5.19 常量表达式

...

条件表达式是核心常量表达式,除非它涉及以下其中一项

...

- 减法(5.7),其中两个操作数都是指针;

您的表达式从一个 const char 指针中减去另一个指针。这似乎使整个事情失去了被视为常量表达式的资格。

在您的情况下,问题中的两个指针本身都是常量值,虚拟值。如果是这样的话,那么理论上可以将它们的减法结果作为常量表达式计算出来,但事实并非如此。任何。

我认为您甚至不需要使用指针减法,或者指针的静态转换在这里可以工作,您需要对引用进行静态转换。以下内容对我有用,至少对于 gcc 来说是这样:

class B { int a; };
class C { int b; };

class A : public B, public C {};

int main()
{
    static const long n=(long)&static_cast<C &>(*(A *)0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)