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