constexpr - Variables and Objects

Contents[Show]

If you declare a variable as constexpr the compiler will evaluate them at compile time. This holds not only true for built-in types but also for instantiations of user-defined types. There are a few serious restrictions for objects in order to evaluate them at compile time.

 

To make the life for you and me easier I will use for built-in types like bool, char, int, and double the name variable. I will call the remaining data types as user-defined data types. These are for example std::string, types from the C++ library and user-defined data types. User-defined types holds typically built-in types.

Variables

By using the keyword constexpr the variable becomes a constant expression.

constexpr double myDouble= 5.2;

 

Therefore, I can use the variable in contexts that requires a constant expression. For example, if I want to define the size of an array. This has to be done at compile time.

For the declaration of constexpr variable you have to keep a few rules in mind.

The variable

  • is implicitly const.
  • has to be initialized.
  • requires a constant expression for initialization.

The rule makes sense. If I evaluate a variable at compile time, the variable can only depend on values that can be evaluated at compile time.

The objects are created by the invocation of the constructor. The constructor has a few special rules.

User-defined types

The class MyDistance from the post Constant expressions with constexpr fulfils all requirements to be initialized at compile time. But what are the requirement?

A constexpr constructor 

  1. can only be invoked with constant expressions.
  2. can not use exception handling.
  3. has to declared as default or delete or the function body must be empty (C++11).

The constexpr user-defined type

  1. can not have virtual base classes.
  2. requirese that each base object and each non-static member has to be initialized in the initialization list of the constructor or directly in the class body. Consequently, it holds that each used constructor (e.g of a base class) has to be constexpr constructor and that the applied initializers have to be constant expressions.

Sorry, but the details are even harder: cppreference.com. To make the theory obvious I define the class MyInt. MyInt shows the just mentioned points. The class has in addition constexpr methods. There are special rules for constexpr methods and functions. This rules will follow in the next post, so we can concentrate in this post on the essentials about variables and user-defined types.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// userdefinedTypes.cpp

#include <iostream>
#include <ostream>

class MyInt{
public:
  constexpr MyInt()= default;
  constexpr MyInt(int fir, int sec): myVal1(fir), myVal2(sec){}
  MyInt(int i){
	myVal1= i-2;
	myVal2= i+3;
  }
  
  constexpr MyInt(const MyInt& oth)= default;
  constexpr MyInt(MyInt&& oth)= delete;
  
  constexpr int getSum(){ return myVal1+myVal2; }
  
  friend std::ostream& operator<< (std::ostream &out, const MyInt& myInt){
    out << "(" << myInt.myVal1 << "," << myInt.myVal2 << ")";  
    return out;
  }

private:
  int myVal1= 1998;
  int myVal2= 2003;

};

int main(){
  
  std::cout << std::endl;
  
  constexpr MyInt myIntConst1;
  MyInt myInt2;
  
  constexpr int sec= 2014;
  constexpr MyInt myIntConst3(2011,sec);
  std::cout << "myIntConst3.getSum(): " << myIntConst3.getSum() << std::endl;
  
  std::cout << std::endl;
  
  int a= 1998;
  int b= 2003;
  MyInt myInt4(a,b);
  std::cout << "myInt4.getSum(): " << myInt4.getSum() << std::endl;
  std::cout << myInt4 << std::endl;
  
  std::cout << std::endl;
  
  // constexpr MyInt myIntConst5(2000);  ERROR
  MyInt myInt6(2000);
  std::cout << "myInt6.getSum(): " << myInt4.getSum() << std::endl;
  std::cout << myInt6 << std::endl;
  
  // constexpr MyInt myInt7(myInt4); ERROR
  constexpr MyInt myInt8(myIntConst3);
  
  std::cout << std::endl;
  
  int arr[myIntConst3.getSum()];
  static_assert( myIntConst3.getSum() == 4025, "2011 + 2014 should be 4025" );
  
}

 

The class MyInt has three constructors. A constexpr default constructor (line 8) and a constructor taking two (line 9) and taking one argument (line 10). The constructor with two arguments is a constexpr constructor. Therefore, it's body is empty. This holds not true for the non-constexpr constructor with one argument. The definition goes on with a defaulted copy-constructor (line 15) and a deleted move-constructor (line 16).  Additionally, the class has two methods, but only the method getSum is a const expression. I can only define the variables myVal1 and myVal2 (line 26 and 27) in two ways if I want to use them in constexpr objects. At first, I can initialize them in the initialization list of the constructor (line 9); at second, I can initialize them in the class body (line 26 and 27). The initialization in the initialization list of the constructor has higher priority. It's not allowed to define both variables in the body of the constructor (line 11 and 12). 

To put the theory to practice, here is the output of the program.

 

 userdefinedTypes

The program shows a few special points:

  • You can use a constexpr constructor at run time. Of course, the instance is no constant expression (line 36 and line 46).
  • If you declare a non-constant expression as constexpr, you will get a compiler error (line 52 and 57).
  • constexpr constructors can coexit with non-constexpr constructors. The same holds true for the methods of a class.

The key observation is: A constexpr object can only use constexpr methods.

But stop. What's the story about the two last lines 62 and 63 in the main function?

The proof

Quite straight forward. They are the twofold proof that the call myIntConst3.getSum() is performed at compile time.

At first, C++ requires that the size of an array has to be a constant expression. At second, static_assert evaluate its expression at compile time. If not, static_assert will not compile.

If I replace the line 63

static_assert( myIntConst3.getSum() == 4025, "2011 + 2014 should be 4025" );

with the line

static_assert( myIntConst4.getSum() == 4001, "1998 + 2003 should be 4001" );

, I will get a compiler error.

 userdefinedTypesError

What's next?

I think, you know it already. In the next post I will write about contexpr functions. They have with C++11 a lot of restrictions that will almost disappear with C++14. constexpr functions in C++14 feels almost like normal functions. Of course, my points about functions will also hold for methods of classes.

 

 

 

 

 

 

 

 

 

 

 

title page smalltitle page small Go to Leanpub/cpplibrary "What every professional C++ programmer should know about the C++ standard library".   Get your e-book. Support my blog.

 

Tags: constexpr

Comments   

0 #1 Pokecoins Free 2016-11-21 09:12
Ahaa, its fastidious dialogue on the topic of this paragraph
at this place at thhis webpage, I have read all that, so at this timje me also commenting at this place.
Quote
0 #2 Deneen 2016-11-21 10:10
Hi there to all, how iis everything,I think every one is getting more frpm this website, and your views are good for neww people.
Quote
0 #3 Miles 2016-11-29 20:42
Ahaa, its pleasant conversation on thhe topic of this article here at this blog,
I have read all that, so noow me aoso commenting here.
Quote
0 #4 Clifton 2016-12-08 00:53
Inspiring story there. Whhat happened after?
Thanks!
Quote
0 #5 Dian 2016-12-11 00:16
Hello there! Would you mind if I share your blog with my zynga group?
There's a lot of folks that I think would really appreciate your content.
Please let me know. Thank you
Quote
0 #6 Wilhemina 2017-03-06 08:54
Great article.
Quote
0 #7 Raleigh 2017-06-30 04:17
Great post. I was checking constantly this weblog annd I'm inspired!

Extremely usefull informnation specially the remaining phase :) I deal with such info a lot.

I used to be looking for this particular information for a long time.
Thank you and good luck.
Quote

Add comment


My Newest E-Books

Latest comments

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 613

All 382635

Currently are 200 guests and no members online