Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a constant pointer be a constant expression?

The following program compiles:

template <const int * P> class Test{};  extern const int var = 42; //extern needed to force external linkage  int main() {     Test<&var> test; } 

This one, however, doesn't, which is a surprise for me:

template <const int * P> class Test{};  extern const int var = 42; //extern needed to force external linkage extern const int * const ptr = &var; //extern needed to force external linkage int main() {     Test<ptr> test; //FAIL! Expected constant expression. } 

Alternative example:

int main() {    const int size = 42;    int ok[*&size]; //OK     const int * const pSize = &size;    int fail[*pSize]; //FAIL } 

I have concluded that a pointer just can't be a constant expression regardless of whether it's const and initialized with a constant expression.

Questions:

  1. Is my conclusion true?
  2. If so, why can't a pointer be a constant expression? If not, why don't the above programs compile?
  3. Does C++0x(C++11, if you will) change anything?

Thanks for any insights!

like image 354
Armen Tsirunyan Avatar asked Sep 12 '11 18:09

Armen Tsirunyan


People also ask

Can a pointer be a constant?

A constant pointer is one that cannot change the address it contains. In other words, we can say that once a constant pointer points to a variable, it cannot point to any other variable. Note: However, these pointers can change the value of the variable they point to but cannot change the address they are holding.

What is a constant expression?

A constant expression is an expression that contains only constants. A constant expression can be evaluated during compilation rather than at run time, and can be used in any place that a constant can occur.

What is difference between constant pointer and constant variable?

Constant pointer refers to a particular variable in its lifetime while a Constant variable always contain same value in its life time. A constant variable is a variable to which value can be assigned only once. Any try to change its value through any operation or reassignment would result in an error.

Is a pointer a variable or constant?

In the pointers to constant, the data pointed by the pointer is constant and cannot be changed. Although, the pointer itself can change and points somewhere else (as the pointer itself is a variable).


2 Answers

It's a bit more complicated. In C++03 and C++11, &var is a constant expression if var is a local static / class static or namespace scope variable. This is called an address constant expression. Initializing a class static or namespace scope pointer variable with that constant expression is guaranteed to be done before any code is run (static initialization phase), because of it being a constant expression.

However only since C++11, a constexpr pointer variable that stores the address &var can also be used as an address constant expression and only since C++11, you can dereference an address constant expression (actually, you can dereference even more - even local array element addresses, but let's keep it ontopic) and if it refers to a constant integral variable initialized prior to the dereference or a constexpr variable, you again get a constant expression (depending on the type and value category, the kind of constant expression may vary). As such, the following is valid C++11:

int const x = 42; constexpr int const *px = &x;  // both the value of "px" and the value of "*px" are prvalue constant expressions int array[*px]; int main() { return sizeof(array); } 

If so, why can't a pointer be a constant expression? If not, why don't the above programs compile?

This is a known limitation in the Standard's wording - it currently only allows other template parameters as arguments or & object, for a template parameter of pointer type. Even though the compiler should be capable of doing much more.

like image 111
Johannes Schaub - litb Avatar answered Sep 22 '22 18:09

Johannes Schaub - litb


It's still not allowed in C++0x. temp.arg.nontype requires:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or
  • the name of a non-type template-parameter; or
  • a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or
  • a constant expression that evaluates to a null pointer value (4.10); or
  • a constant expression that evaluates to a null member pointer value (4.11); or
  • a pointer to member expressed as described in 5.3.1.

original answer:

  1. In C++03, only integral expressions can be constant expressions.
  2. Because the standard says so (naturally).
  3. In C++0x, n3290 includes examples using constexpr on a pointer. So what you are trying should now be possible, although you must now use the constexpr keyword instead of top-level const.

There's also a gcc bug involved, g++ rejects the standard draft's own examples of valid constexpr usage.

like image 24
Ben Voigt Avatar answered Sep 18 '22 18:09

Ben Voigt