How to constexpr construct C++ object containing reinterpret_cast pointer?

mark_r via gcc-help gcc-help@gcc.gnu.org
Tue Feb 11 22:27:00 GMT 2020


Jonathan Wakely-4 wrote
> It has been reported to be impossible to implement in one major
> compiler implementation. Constexpr evaluation is effectively a
> compile-time interpreter of C++, and has a stricter type system and
> restrictions on which parts of the language are possible.

I understand that constexpr evaluation effectively requires a compile-time
interpreter. I don't understand why the capability is impossible but may do
research to find out more, including why the stricter type system
restrictions are necessary. Again, I'd like to find an example of "if you
did that here's what it would break". 



Jonathan Wakely-4 wrote
> reinterpret_cast breaks the type system to tell the compiler that you
> know something it doesn't about the actual types present at runtime.
> That is not the case in constexpr evaluation, the compiler has
> complete knowledge of the types involved, and knows you're lying.
> 0x4000000 is not a pointer value.

We're going around in circles a little bit, but I know it breaks the type
system. I *do* know something about the runtime types that the compiler
doesn't. I also know that generating the machine instructions to use
0x40000000 as a pointer to an Object and the ones to offset that for access
to its members, and invoking Object::methods with 0x40000000 as the "this"
pointer, will work perfectly. I just need a way to communicate that to the
compiler.

But I see now that this is the disconnect between the you and me. My
colloquial understanding of reinterpret_cast as meaning "use the bits as-is
without regard to anything else" is incorrect. The site
https://en.cppreference.com/w/cpp/language/reinterpret_cast says:

    Unlike static_cast, but like const_cast, the reinterpret_cast expression
does not compile to any CPU
    instructions (except when converting between integers and pointers or on
obscure architectures where
    pointer representation depends on its type).

Ignoring the "obscure  architectures" part, it's the "except when converting
between integers and pointers" clause. In my defense, my simplistic view is
quite common. From the admittedly garbage website
https://www.geeksforgeeks.org/reinterpret_cast-in-c-type-casting-operators/
page:

    reinterpret_cast is a type of casting operator used in C++.
    - It is used to convert one pointer of another pointer of any type, no
matter either the class is related to
      each other or not.
    - It does not check if the pointer type and data pointed by the pointer
is same or not.

Or that company that never hesitated to make incompatible changes to the
language at will in their "Visual C++" (or whatever) compiler:
https://docs.microsoft.com/en-us/cpp/cpp/reinterpret-cast-operator?view=vs-2019

    reinterpret_cast Operator
    11/04/2016
    2 minutes to read
    Allows any pointer to be converted into any other pointer type. Also
allows any integral type to be converted
    into any pointer type and vice versa.

I agree that your views are more rigorously correct.



Jonathan Wakely-4 wrote
> On Tue, 11 Feb 2020 at 05:25, mark_r wrote:
>> Nor likewise why reinterpret_cast to a pointer type is illegal
> 
> Because integers are not pointers.
> 
> What you really want is a way to provide a literal pointer value, or
> some other compile-time pointer value. There is no reason
> reinterpret_cast has to be the way to do that. Again, using
> reinterpret_cast is just a means to an end, not your end goal.

Especially in view of the above, that would be fine for me. I just want to
get it done.



Jonathan Wakely-4 wrote
> So use the helper method.

As I said in my previous post, that's what I'll do for the conceivable
future, if not (as is likely) forever.


Jonathan Wakely-4 wrote
> Right, it's just an assertion that says you expect the object to be
> statically initialized. If the compiler needs to do dynamic
> initialization for a constinit variable, the program would be
> ill-formed (as opposed to just silently changing from static
> initialization to dynamic initialization if you accidentally make a
> change to the code that requires dynamic init).
> 
> I used constinit to prove that the initialization is not dynamic.
> 
>> would the following code compile and be static initialized?
> 
> No, you're still trying to pass a non-constant to a constexpr constructor.

So where we stand is:

1) It is impossible to have static initialization for an object which has
private/protected Object* const member.
2) The best workaround is to have an integer type member which has the
numeric address of the Object and reinterpret_cast it Object* when needed,
likely through a helper method.
3) I might be able to request a GCC (or C++ standard) extension to allow
#1's capability, but if granted it wouldn't use either the constexpr or
constinit keyword or semantics.

Thanks for your time and input. I'll have to think about if and how to
pursue the topic further.
 




--
Sent from: http://gcc.1065356.n8.nabble.com/gcc-Help-f629689.html



More information about the Gcc-help mailing list