Using constexpr method inside another method of the same class in C ++

As expected, I can compile the sample below without any problems

// first_sample.cpp struct sample_struct { constexpr int sample_method() { return 5; } }; int main() { sample_struct sample_object; constexpr int sample_variable = sample_object.sample_method(); return 0; } 

But I can not compile the following example for a reason

'this' is not a constant expression

 // second_sample.cpp struct sample_struct { constexpr int sample_method_first() { return 5; } void sample_method_second() { constexpr int sample_variable = sample_method_first(); /* Do something with sample_variable */ } }; int main() { return 0; } 

I already know how to solve this "problem", so I do not ask permission. I am asking for a reasonable explanation as to why I am allowed to call the constexpr method from a non-constexpr object , while I am not allowed to call the same constexpr method inside another method (from the non-conference 'this').

+4
source share
2 answers

In the C ++ standard [dcl.constexpr] / 9:

The constexpr specifier used in declaring an object declares the object as const. Such an object must be of literal type and must be initialized. [...] Otherwise, or if the constexpr specifier is used in the link description, each complete expression that appears in its initializer must be a constant expression.

Now the compiler implicitly adds this-> to the member function call, as specified in [expr.call] / 1

In the case of implicit access to a class member, the implied object is the one it points to. [Note: a call to a member function of the form f() interpreted as (*this).f() (see 9.3.1). -end note]

As jogojapan noted (see chat discussion ), in the official C ++ 11 Standard, this can occur as a postfix expression in the access of class members according to [expr.const] / 2, which is what is here. But Issue 1369 permission prohibits the use of this in constant expressions; however, invocation function substitution may allow the use of this in the context of the constexpr function, replacing it with the prvalue pointer.

The C ++ 14 project removes the subclause on replacing the function call in favor of the exception from [expr.const] / 2, explicitly allowing the use of this in the context of the constexpr function (<in this case, the same as the substitution of the function call is effective).


Well, this is not very "reasonable", since it does not give a reason why it is specified in this way, it gives only the reason why the compiler rejects it.

+3
source

Function A constexpr can be called in any context, constant expression or not. (And your sample_method_second is not even constexpr .) But the constexpr object must be evaluated at compile time.

So what sample_method_second does, ask the compiler to use this to get the result of sample_method_first at compile time. Clearly this is not possible.

The difference is that in the first example, the scope of main allows the compiler to call the method on sample_object . But the ability to evaluate the value of one object does not apply to all potential objects in the program, which is what sample_method_second does.

The solution (well, except to create a sample_method_first that is independent of this using static ) should not declare sample_variable as constexpr . If you use it in a way that constexpr requires, then your design is erroneous because one member function really needs several (potentially infinite) implementations in the final program.

Remember that each potential different value of the legitimate variable constexpr can create a new instance of the template, otherwise an organized compilation of switch or halt with static_assert . Try doing this retroactively at runtime!


As to why the first case is allowed:

 sample_struct sample_object; constexpr int sample_variable = sample_object.sample_method(); 

What happens here is a call to the constexpr function, and the rule for this excludes

- a call to a function other than the constexpr constructor for a literal class, a constexpr function, or an implicit call to a trivial destructor (12.4)

There is simply no requirement that the object be constexpr , because if something needs to be constant in order to evaluate the inside of the function or use the result of the function, the evaluation will be erroneous according to one of the other rules, such as the lvalue-to-rvalue conversion. You won’t be able to modify sample_method to actually access anything, and you will complain that sample_object not declared constexpr or its address is not constant if you try to use this value directly.

0
source

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


All Articles