📜 ⬆️ ⬇️

The "constexpr" functions do not have the "const" specifier

Just wanted to warn you: C ++ 14 will not be backward compatible with C ++ 11 in one aspect of the constexpr functions.

In C ++ 11, if you define a constexpr member function, it will implicitly get the const qualifier:
 // C++11 struct NonNegative { int i; constexpr int const& get() /*const*/ { return i; } int& get() { return i; } }; 

The first function declaration get will get the const qualifier, even if we do not explicitly specify it. Consequently, these two functions are overloaded: const and non- const versions.

In C ++ 14, this will be no longer the case: both declarations will determine the same, non- const version of the member function with different return values ​​- this will lead to a compilation error. If you have already started using the constexpr functions and hope for the implicit const specifier, then I advise you to start adding it explicitly so that your code continues to compile if you decide to switch to C ++ 14 compilers.

What is wrong with implicit const ?


Problems will begin if you try to use our type as follows:
 // C++11 constexpr int i = NonNegative{2}.get(); // ERROR 

According to the (somewhat unusual) C ++ rules, when choosing a member function for a temporary object, a non- const version is preferable to a const version. Our non- const get member function is not constexpr , so it cannot be used to initialize the constexpr variable and we get an error at the compilation stage. We cannot do this constexpr function, because it will automatically add the const specifier ...
')
I said that the rules for choosing the best function are unusual, because they contradict a bit how we choose the best non-name function for temporary objects. In this case, we prefer the const lvalue link to the non- const version:
 // C++11 constexpr int const& get(NonNegative const& n) { return ni; } constexpr int& get(NonNegative& n) { return ni; } NonNegative N = readValue(); constexpr int * P = &get(N); int main() { *P = 1; } 

See what happens: the global variable N not a constant. Therefore, the second, non- const overloaded function is selected to be called when the pointer P initialized. But the non- const function still has the constexpr ! That's because the " constexpr means const " rule applies only to the implicit this argument of a non-static member function. constexpr function can get a reference to a non- const object and return a reference to a non- const sub-object. There are no problems here: the address of the global object is constant and known at compile time. However, the value at address P not permanent and can be changed later.

If the previous example looks somewhat contrived, consider the following, more realistic example:
 // C++11 constexpr NonNegative* address(NonNegative& n) { return &n; } NonNegative n{0}; // non-const constexpr NonNegative* p = address(n); 

Everything works fine here, 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 implicitly defined with the const specifier, this is of type NonNegative const* and cannot be converted to NonNegative* .

It should be noted that this is not the member function itself is const , but the implicit ( this ) argument of the function. A member function declaration can be rewritten in pseudo-code as:
 // PSEUDO CODE struct NonNegative { // ... constexpr NonNegative* maddress(NonNegative const& (*this)); }; 

And this implicit function argument, unlike other function arguments, receives the (sometimes undesirable) const specifier.

This asymmetry will be removed in C ++ 14. If you want the const specifier for an implicit argument ( this ), you should add it yourself. The following code will be valid in C ++ 14:
 // C++14 struct NonNegative { int i; constexpr int const& get() const { return i; } constexpr int& get() { return i; } }; 

Source: https://habr.com/ru/post/184250/


All Articles