This is just a word of caution. C++14 will not be backwards compatible with C++11 in one aspect of constexpr functions.

In C++11, when you define a constexpr member function, it implicitly obtains a const qualifier:

// C++11 struct NonNegative { int i; constexpr int const& get() /*const*/ { return i; } int& get() { return i; } };

The first declaration of function get obtains a const qualifier even though we did not type it. Therefore, the two declarations declare two function overloads: a const and a non- const one.

In C++14 this will no longer be the case: the two declarations will define the same non- const member function with two different return types: this will cause a compilation error. If you have already started playing with constexpr functions and you rely on this implicit const qualifier, I suggest that you start adding it explicitly, so that your code still compiles when you switch to C++14 compilers.

What’s wrong with implicit const ?

The problem starts when you try to use our type like this:

// C++11 constexpr int i = NonNegative{2}.get(); // ERROR

The (somewhat unusual) rules of C++ dictate that when picking a member function on a temporary class object, the non- const variant is a viable candidate, and in fact preferred to the const one. Our selected non- const member function get is not constexpr , so it cannot be used to initialize a constexpr variable and we get a compile-time error. We cannot fix it by making the non- const overload constexpr , because this would imply the const qualifier…

I said that the rules of best function matching are unusual, because they are quite the opposite when we are selecting the non-member function for a temporary object. In that case we choose const lvalue reference variant, and the to non- const one is not even a viable match:

int const& fget(NonNegative const& n) { return n.i; } int& fget(NonNegative& n) { return n.i; } int i = fget(NonNegative{2});

In the case above we select the first overload: a reference to non- const lvalue from the second overload cannot be bound to a temporary.

The above ‘irregularity’ is a problem related to how member functions are matched, and not directly related to constexpr functionality. However, there is another irregularity added along constexpr to C++11. If we define non-member constexpr getters, no implicit const is added:

// C++11 constexpr int const& get(NonNegative const& n) { return n.i; } constexpr int& get(NonNegative& n) { return n.i; } NonNegative N = readValue(); constexpr int * P = &get(N); // non-const overload int main() { *P = 1; }

Observe what happens. The global N is not a constant. Therefore the second, non- const overload is picked in line 6. But the non- const overload is still a constexpr function! Because rule “ constexpr implies const ” only applies to the implied this argument of non-static member functions. A constexpr function can take a reference to non- const object and return a reference to its non- const sub-object. This is all fine: we do not know the value of N , but by only passing references around and not reading the value we are not doing anything impossible. Next, we take the address to N ’s sub-object. This is still fine: the address of a global is constant — known at compile-time. However, the value at the address P is not constant and can be later assigned to.

If the above example looks too esoteric, consider the following, a bit more realistic one:

constexpr NonNegative* address(NonNegative& n) { return &n; } NonNegative n{0}; // non-const constexpr NonNegative* p = address(n);

This works fine. But if you try to make address a member function, it will stop working:

// C++11 struct NonNegative { // ... constexpr NonNegative* maddress() { return this; } // ERROR }; NonNegative n{0}; // non-const constexpr NonNegative* p = n.maddress();

This is because maddress is implicitly const , this has type NonNegative const* and cannot be converted to NonNegative* .

Note that it is not a member function that is really const , but the implicit ( this ) function argument. The declaration of the member function could be depicted in a pseudo language as:

// PSEUDO CODE struct NonNegative { // ... constexpr NonNegative* maddress(NonNegative const& (*this)); };

And this implicit function argument, unlike any other function argument, obtains a (sometimes unwanted) const qualifier.

This asymmetry will be removed in C++14. If you want a const qualifier for the implicit argument ( this ), you need to type it yourself. The following is going to be valid in C++14:

// C++14 struct NonNegative { int i; constexpr int const& get() const { return i; } constexpr int& get() { return i; } };

Further reading