Skip to content

constexpr

November 14, 2011

The keyword constexpr specifies that an expression must be constant at compile time. This doesn’t necessarily mean that the compiler will take advantage of this and produce optimal code, but at least it might, and it will compute constexpr values when forced. In GCC, it appears that you must use at least -O1 to generate constexpr code, otherwise the full code is evaluated at runtime.

The most simple use is to specify that a variable’s value is given by a constexpr:

constexpr int x = 42+42;

Any uses of x are now guaranteed to have the constant value 84 instead of computing 42+42 at runtime.

There are also constexpr functions. A constexpr function must be defined in terms of a single return expression, the subexpression of which must be a constexpr. For example:

constexpr int add(int a, int b)
{
  return a + b;
}

Note that this function can still be called with non-const arguments, in that case it will be evaluated at run time. However, it is guaranteed to be a constexpr when it is called with constexpr arguments.

There are also constexpr constructors and member functions for classes.

Suppose that you need some computation to be compile time constant, but the most natural way to express it is with a class, then you can do that with constexpr objects, constructors and member functions.

The following is an example of how to use constexpr with a class. There is a class LineSegment which represents a line segment, and has a function to compute the midpoint of a line segment.

#include <utility>

class LineSegment
{
  public:
  constexpr LineSegment(double ax, double ay, 
    double bx, double by)
  : m_ax(ax), m_ay(ay), m_bx(bx), m_by(by)
  {}

  constexpr
  std::pair<double, double>
  midpoint()
  {
    return std::make_pair((m_ax+m_bx)/2, (m_ay+m_by)/2);
  }

  private:
  double m_ax, m_ay, m_bx, m_by;
};
 
constexpr LineSegment line(0,0, 10,10);

int main()
{
  return line.midpoint().first;
}

By declaring the variable line as a constexpr, we are saying that its value is constant, and we are allowing ourselves to query it with constexpr member functions. Since it is constant, it must also be constructed with a constexpr constructor. The constructor is restricted to having an empty body, and all members must be initialised with an initialiser list whose expressions are also constexpr. The midpoint can also be computed with a constexpr function since the whole variable is constexpr. Finally, we can use std::pair as a constexpr because its constructor is also declared as constexpr.

Digging into the assembly that is generated, we can verify that the result is as expected.

main:
  .LFB62:
  .cfi_startproc
  movl  $5, %eax
  ret
  .cfi_endproc

All this does is return 5, which is exactly what we wanted.

About these ads

From → Language

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: