How can constexpr pointers exist and constevel function return a pointer at compile time?

161 views Asked by At

I was going through the topics of constexpr and consteval and found the below,

  1. We can have pointers that are of type CONSTEXPR
  2. A CONSTEVAL function can return a pointer of a CONSTEXPR variable

and my question here is that, how is the above 2 possible?

The above 2 questions because, as far as I am aware, all the variables are created in the memory during runtime and pointer is the address of that memory.

So, how can pointer of type CONSTEXPR exist (since CONSTEXPR variables have to be initialized at compile time)? and how can a CONSTEVAL function return a pointer of CONSTEXPR variable during the compile time?

   #include <iostream> 

   constexpr int a{1};

   consteval const int* aptrfunc()  //How can this function return a pointer at compile time
   {
       return &a;
   }

   int main()
   {
        constexpr const int* aptr{&a};   //How can this exist at compiletime?
        std::cout<<aptr<<'\n';           //Prints address of a
        std::cout<<aptrfunc()<<'\n';     //Prints address of a
        return 0;
    }
2

There are 2 answers

0
user12002570 On

The above 2 questions because, as far as I am aware, all the variables are created in the memory during runtime

Yes but not all of them have a fixed address.

As far as the standard is concerned, a constexpr pointer is allowed to point to an object that remains at a fixed address. And an object defined outside any function(global object) have a fixed address and so it's address can be used to initialize a constexpr pointer.

As in your example, a is a global int and hence remains at fixed address, so a constexpr pointer can be made to point to it.

An implementation/compiler might deal with such(constexpr) pointers symbolically but that is an implementation detail.

4
JaMiT On

pointer is the address of that memory

Well, not exactly. The phrasing used by cppreference.com is "represents the address". It is more important for a pointer to allow the program to access what it points to than for a pointer to have a certain value or bit pattern. You are getting hung up on knowing the certain value.

There is a lot you can do with pointers without knowing exact addresses, if you think abstractly. You can, for example, determine if two pointers point to the same address. You might not know the exact address, just that they are the same. In practice, the addresses that are valid for constexpr values are known at compile time up to an offset that is supplied by the operating system at runtime, and that is fixed for the entire execution. This is enough to determine whether or not two pointers are equal. Similarly, in places where a constant expression is required, "up to an offset" is sufficient for the compiler to do what it needs to do.

Interestingly, one place where a constant expression is not required is an operand to the streaming operator. That is, in the expression std::cout<<aptr, it is not required that the compiler be able to determine exactly which characters will be displayed. Instead, the output characters can be determined at runtime. In this respect, it is not possible to view the value of aptr until the program executes. However, at compile time, despite not being able to display an exact value, it is known that the expression aptr represents the address of a, and that is good enough for all (legal) compile-time processing.