A basic example with "constexpr" doesn't compile - c++

I'am learning C++ so I'am currently reading the book "C++ Primer".
I was reading some examples about the "constexpr variables" and I just want to try a basic code that I just wrote but it doesn't compile I don't know why.
This is the code :
#include <iostream>
using namespace std;
int j = 8;
const int *p = &j;
int main()
{
constexpr int i = *p; // *p should be 8.
return 0;
}
The compiler says : "the value of 'p' is not usable in a constant expression"
If I replace the "constexpr" by "const" no problem at all but I think that because the value of *p should be known at compile time there shouldn't be any problems.
I don't know where I made a mistake.
(Please be tolerant my first language is French)

The reason this does not compile is because J is not const or constexpr.
Also note P is "just" const pointer.
This means *P can not be changed, but P itself is free to be changed.
Here is an example:
int f(){
int a = 5;
int b = 6;
int *p = nullptr;
p = &a; // *p -> a -> 5
p = &b; // *p -> a -> 6
return *p;
}
I want to clarify something for const vs constexpr:
const is not constexpr, but some for some primitive types there is no difference:
This compiles:
const int j = 8;
constexpr const int *p = &j;
int main(){
constexpr int i = *p;
return i;
}
Also this compiles:
constexpr int j = 8;
constexpr const int *p = &j;
int main(){
constexpr int i = *p;
return i;
}
However this does not compiles:
const int j = 8;
const int *const p = &j;
int main(){
constexpr int i = *p;
return i;
}

It seems the fundamental misunderstanding you have is the difference between an object being const vs constexpr. A variable being const means that it's logically const, i.e. the value cannot be changed once it's initialized. That does not mean that the value is known at compile time, which is what constexpr signifies.
For some type T
T t = {}; // not const, not constexpr
const T t = {}; // const, but not constexpr
constexpr T t = {}; // constexpr, also implies const
All good so far, but there's an additional wrinkle: a variable of integral or enumeration type that is const and is assigned a constant expression, is also constexpr. There are good reasons for this difference, but what that means is:
const int i = 42; // i is int, and const, so it's also constexpr !!
And of course, if you want to use an expression as a constant expression, it must have been declared as a constexpr variable or function.

Related

What types of objects can constexpr pointers point to?

cppreference.com says:
A constexpr specifier used in an object declaration implies const.
But I tried to make a constexpr pointer hold the address of a const object of the same base-type but the compiler gave me an error:
const int a = 1;
int main(){
constexpr int *b = &a;
return 0;
}
So, what types can a constexpr pointer point to?
The issue here is not with constexpr. If you said
int *b = &a;
You'd get the same error. i.e. "invalid conversion from const int* to int*"
We can fix that by making it a pointer to a const int.
int const *b = &a;
Now we can add constexpr, and yes, constexpr does imply const
constexpr int const *b = &a;
where b is in fact const. This is exactly the same as the following
constexpr int const * const b = &a;
//^^^^^
// this const is made redundant by the constexpr.
Your example doesn't compile because 'a' is a 'const int', and requires a 'constexpr const int' pointer to point to it.

Does constexpr in pointers make a difference

What is the difference between constexpr int *np = nullptr and int const *np = nullptr?
np is a constant pointer to an int that is null, in both cases. Is there any specific use of constexpr in context of pointers.
If you try to do anything with the pointer and use the result in a constant expression, then the pointer must be marked as constexpr. The simple example is pointer arithmetic, or pointer dereferencing:
static constexpr int arr[] = {1,2,3,4,5,6};
constexpr const int *first = arr;
constexpr const int *second = first + 1; // would fail if first wasn't constexpr
constexpr int i = *second;
In the above example, second can only be constexpr if first is. Similarly *second can only be a constant expression if second is constexpr
If you try to call a constexpr member function through a pointer and use the result as a constant expression, the pointer you call it through must itself be a constant expression
struct S {
constexpr int f() const { return 1; }
};
int main() {
static constexpr S s{};
const S *sp = &s;
constexpr int i = sp->f(); // error: sp not a constant expression
}
If we instead say
constexpr const S *sp = &s;
then the above works works. Please note that the above does (incorrectly) compiled and run with gcc-4.9, but not gcc-5.1

make 'const' work with the result of type traits

int main(int argc, char* argv[]) {
const int i = 10;
using Type = typename std::conditional<false, int, int&>::type;
const Type r = i; // It seems this 'const' does not have any effect.
std::cout << r << std::endl;
}
The above code cannot compile on gcc4.8.1 -std=c++11, and the error message goes as following: "invalid initialization of reference of type 'Type {aka int&}' from expression of type 'const int'. But, it will work if I change the code like this:
int main(int argc, char* argv[]) {
const int i = 10;
using Type = typename std::conditional<false, const int, const int&>::type;
Type r = i;
std::cout << r << std::endl;
}
Is there any body can show me the reason?
In the first example, the const has no effect because it binds to the wrong type: after the reference rather than before. See https://www.securecoding.cert.org/confluence/display/cplusplus/DCL33-CPP.+Never+qualify+a+variable+of+reference+type+with+const+or+volatile for some details that may help, but basically:
const int& // reference to immutable int
int const& // reference to immutable int
int& const // immutable reference to int
Of course, all references are immutable (cannot be reseated), so the last one, which you have, is a bit useless. It happens because you apply the const after the reference has already been applied to the type, which gives you the third example I wrote rather than the first or second.
You can also change
const int i = 10;
to
int i = 10;
to make it work.
when you say
using Type = typename std::conditional<false, int, int&>::type;
it is equivalent to:
typedef int& Type;
When you say
const Type r = i;
What you are saying is
int& const r = i;
That's not the same thing as
const int& r = i;
The difference between those was explained by John Zwinck in his answer.

constexpr initializing with pointers

I am trying to initialize a constexpr declaration with a pointer to int which is a const object. I also try to define an object with a object that is not a const type.
Code:
#include <iostream>
int main()
{
constexpr int *np = nullptr; // np is a constant to int that points to null;
int j = 0;
constexpr int i = 42; // type of i is const int
constexpr const int *p = &i; // p is a constant pointer to the const int i;
constexpr int *p1 = &j; // p1 is a constant pointer to the int j;
}
g++ log:
constexpr.cc:8:27: error: ā€˜& iā€™ is not a constant expression
constexpr.cc:9:22: error: ā€˜& jā€™ is not a constant expression
I believe it is because the objects in main have no fixed addresses, thus g++ is throwing error messages back at me; how would I correct this? Without using literal types.
Make them static to fix their addresses:
int main()
{
constexpr int *np = nullptr; // np is a constant to int that points to null;
static int j = 0;
static constexpr int i = 42; // type of i is const int
constexpr const int *p = &i; // p is a constant pointer to the const int i;
constexpr int *p1 = &j; // p1 is a constant pointer to the int j;
}
This is known as an address constant expression [5.19p3]:
An address constant expression is a prvalue core constant expression
of pointer type that evaluates to the address of an object with static
storage duration, to the address of a function, or to a null pointer
value, or a prvalue core constant expression of type std::nullptr_t.

about "int const *p" and "const int *p "

#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int i1 = 0;
int i2 = 10;
const int *p = &i1;
int const *p2 = &i1;
const int const *p3 = &i1;
p = &i2;
p2 = &i2;
p3 = &i2;
cout << *p << endl
<< *p2 <<endl
<< *p3 <<endl;
return 0;
}
The code can be compiled with both VC6.0 and VC2010.
But I have questions as blow:
const int *p = &i1;
It means what the "p" points can not be modified,but p can not be modified,am I right?
so
p = &i2;
this line can be complied,yes?
This line:
int const *p2 = &i1;
In my mind,this means p2 can not be modified while what p2 points can be changed, am i right?
Why the
p2 = &i2;
can be compiled?
About this line:
const int const *p3 = &i1;
p3 = &i2;
Oh,god... I am crazy. I have no idea why this line can be compiled with no error...
Can any body help me?
Another code which confused me is here:
class Coo2
{
public:
Coo2() : p(new int(0)) {}
~Coo2() {delete p;}
int const * getP() const
{
*p = 1;
return this->p;
}
private:
int* p;
};
why this code can be compiled?
In
int const * getP() const
I have change the value or *p !
Here we consider 4 types of pointers declarations:
int * w;
It means that w is a pointer to an integer type value. We can modify both the pointer and its content. If we initialize w while declaration as below:
int * w = &a;
Then, both of below operations are viable:
w = &b;(true)
*w = 1;(true)
int * const x;
It means x is a constant pointer that points to an integer type value. If we initialize x while declaration as below:
int * const x = &a;
Then, we cannot do: x = &b;(wrong) because x is a constant pointer and cannot be modified.
However, it is possible to do: *x = 1;(true), because the content of x is not constant.
int const * y; //both mean the same
const int * y;
It means that y is a pointer that points to a constant integer value. If we initialize y while declaration as below:
int const * y = &a;
Then, it is possible to do: y=&b;(true) because y is a non-constant pointer that can point to anywhere.
However, we cannot do: *y=1;(wrong) because the variable that y points to is a constant variable and cannot be modified.
int const * const z; //both mean the same
const int * const z;
It means that z is a constant pointer that points to a constant integer value. If we initialize z while declaration as below:
int const * const z = &a;
Therefore, non of below operations are viable:
z = &b;(wrong)
*z = 1;(wrong)
With the help of pointer, you can actually do two things.
You can change the data it is pointing to but cannot point to a different memory location.
You can point it to a different memory location but cannot change the data it is pointing to.
Now, when you say, int const* ptr or int const* ptr, it falls under first category. It's same as -
const int num = 5; // Both mean the same.
int const num = 5;
To, actually not able to change to a different location, i.e., pointer to a constant location but be able to modify the data, the semantics should be int* const. Since the content of the pointer is a constant, it should be initialized while declaration.
int num = 5;
int* const ptr; // Wrong
ptr = &num; // Wrong
int* const ptr = &num;
*ptr = 100;
However, there is a third kind. Constant pointer to a constant location, which can neither point to a different memory location nor change the data it is pointing to. ( i.e., const int* const )
And now answering the questions, the first two can be compiled because they are not pointing to constant locations. So, they can be modified at later stages too.
const int const *p3 = &i1;
p3 = &i2; // Wrong
In the above snippet, p3 is a constant pointer to a constant location. So, it cannot be modified.
const at the end of a member function says it is not going to change the state of the object. When you say *p = 1;, you are not changing the state of the object. p still points to the same memory location. This is not allowed to do -
int const * Coo2::getP() const
{
*p = 1; // State of `p` is still not modified.
p = new int ; // Error: Changing the memory location to which p points.
// This is what changing the state of object mean and
// is not allowed because of `const` keyword at the end of function
return this->p;
}
Hope, now you understand why the program compiles :)
int const * p; and const int * p are the same. It is when the const comes after the * that
the semantics of the expression change.
I know, it's crazy.
const int *p = &i1;
int const *p2 = &i1;
These both declare non-const pointers to const data.
That is, using p, you cannot change the data it points to. However, you can change the pointer itself, for example, by assigning as p = &i2 which is legal. But *p = 87987 is illegal, as the data p points to is const!
--
int * const p = &i1;
This declares const pointer to non-const data. That is, p=&i2 is illegal, but *p = 98789 is legal.
--
const int * const p = &i1;
This declares const pointer to const data. That is, now both p=&i2 and *p=87897 are illegal.
The two are exactly the same. What matters is the position of the qualifier relative to the asterisk (*):
int const *p; // normal pointer to const int
const int *p; // ditto
int *const p; // const pointer to normal int (rarely useful)
int const * const p; // const pointer to const int
Here is a pointer to a constant:
const int* p;
The following statement is illegal, because it attempts to change the
value of a constant:
*p = 3;
But this one is legal, because the pointer itself is not a constant:
p = &x;
On the other hand, this declaration shows a constant pointer to a variable.
int* const p;
In that case, the following statement is legal, as the variable can be changed:
*p = 3;
but this one is not, because it attempts to change the value of a constant.
p = &x;
Reference link:http://faculty.cs.niu.edu/~freedman/241/const-ptrs.txt
No, the const keyword before the * means that the variable you are pointing to is a "const" variable and only it can not be modified.
If you want a pointer that can't be reassigned then you need to declare it as Foo* const p = &bar;
If you want a pointer that points to a "const" object that can't be reassigned declare it as const Foo* const p = &bar
It is perfectly fine to have a pointer of const int* foo be assigned to a pointer of const int* const bar just like it is fine to have an int's value assigned to a const int. Think of it in the same manner.
int const * is the same as const int *
Succinctly; each combination of read/write int & pointer;
int main() {
int a,b;
int* w; // read/write int, read/write pointer
w= &b; // good
*w= 1; // good
int* const x = &a; // read only pointer, read/write int
// x = &b; // compilation error
*x = 0; // good
int const * y; // read/write ptr, read only int
const int * y2; // " " "
y = &a; // good
// *y = 0; // compilation error
y2 = &a; // good
// *y2 = 0; // compilation error
int const * const z = &a; // read only ptr and read only int
const int * const z2 = &b; // " " " "
// *z = 0; // compilation error
// z = &a; // compilation error
// *z2 = 0; // compilation error
// z2 = &a; // compilation error
}