constexpr functions.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; } }; 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.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.const ? // C++11 constexpr int i = NonNegative{2}.get(); // ERROR 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 ...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; } 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. // C++11 constexpr NonNegative* address(NonNegative& n) { return &n; } NonNegative n{0}; // non-const constexpr NonNegative* p = address(n); 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(); maddress implicitly defined with the const specifier, this is of type NonNegative const* and cannot be converted to NonNegative* .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)); }; const specifier.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