Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why typecasting an integer literal to a pointer value results in a non-const expression?

I'm trying to write a struct to calculate the pointer offset between a base and a derived class as a constant expression in C++03. The code is as follows:

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

The code compiles in GCC, but not in clang and VC. The error produced by clang and VC basically says that the initializer is not a constant expression with clang further underlines the sub-expression (Derived*const)(1u << 7).

So, my question is what the standards say about this? And if the initializer does not qualify as a constant expression according to the standards, then what is the reasoning behind this?

UPDATE: For your interest, I've found these two discussions:

"Initializer element is not constant" error for no reason in Linux GCC, compiling C

About cast in integer constant expression (in standard C)

But I don't think the same rules apply to C++.

like image 268
Lingxi Avatar asked Dec 25 '14 10:12

Lingxi


1 Answers

This is not a constant expression, according to my reading of the standard:

5.19 Constant expressions

...

A conditional-expression is a core constant expression unless it involves one of the following

...

- a subtraction (5.7) where both operands are pointers;

Your expression subtracts one const char pointer from another. That seems to disqualify the whole thing from being considered as a constant expression.

In your case, both pointers in questions themselves are constant values, dummy values. If that's the case, then it is theoretically possible to figure out the result of their subtraction, as a constant expression, but it's not. Whatever.

I don't think you even need to use pointer subtraction, or that a static cast of a pointer would work here, you need to do a static cast on a reference. The following works for me, at least with 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;
}
like image 107
Sam Varshavchik Avatar answered Oct 07 '22 18:10

Sam Varshavchik