Constexpr functions that don't use this?

Please consider the following two C ++ 14 programs:

Program 1:

struct S { constexpr int f() const { return 42; } }; S s; int main() { constexpr int x = sf(); return x; } 

Program 2:

 struct S { constexpr int f() const { return 42; } }; int g(S s) { constexpr int x = sf(); return x; } int main() { S s; return g(s); } 

Are both or both of these programs poorly formed?

Why / why not?

+9
source share
3 answers

Both programs are well formed. The C ++ 14 standard requires sf() be a constant expression, because it is used to initialize the constexpr variable, and in fact it is an expression of the main constant, because there is no reason not to. The reasons why an expression may not be an expression of a basic constant are listed in section 5.19 p2. In particular, it says that evaluating an expression would have to do one of several things, none of which were done in your examples.

This may be surprising since, in some contexts, passing a non-constant expression to the constexpr function can result in a non-constant expression, even if the argument is not used. For instance:

 constexpr int f(int) { return 42; } int main() { int x = 5; constexpr auto y = f(x); // ill-formed } 

However, the reason this is not properly formed is to convert a mutable expression in an lvalue to an rvalue, which is one of the reasons that evaluating an expression is not allowed. Converting from lvalue to rvalue does not occur when sf() called.

+6
source

I can’t find a convincing passage or example in the standard that directly solves the problem of calling the constexpr member function on a non-constexpr instance, but here are some of them that can help (from the N4140 project)

[C++14: 7.1.5/5] :

For a non-template, non-default constexpr function or non-default, non-default, not inheriting constexpr , if there are no argument values, so the function or constructor call can be evaluated by subexpressing the main constant expression (5.19), the program is poorly formed; No diagnostics required.

 constexpr int f(bool b) { return b ? throw 0 : 0; } // OK constexpr int f() { return f(true); } // ill-formed, no diagnostic required 

From this, I believe that the program is not completely poorly formed just because the constexpr function has a possible path without constance.

[C++14: 5.19] :

 int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK: constructor call initializes // m with the value 42 constexpr int w = A(false).m; // error: initializer for m is // x, which is non-constant 

This is somewhat closer to your sample programs, here the constexpr constructor can refer to the non-constexpr variable depending on the value of the argument, but there is no error if this path is not actually executed.

So, I do not think that any program that you submitted should be poorly formed, but I can not offer convincing evidence :)

+1
source

This sounds like a quiz question and is not presented by the student, but the professor is testing the publication on stackoverflow, but let him see ...

Let's start with the rule of definition. It is clear that no version violates this, so they both transmit this part.

Then, to the syntax. They also do not have syntax errors, they will compile without problems if you do not mind the possible combination of syntax and semantic problem.

Firstly, a simpler semantic problem. This is not a syntax issue, but f() , in both versions, is a member of the structure, and the function does not explicitly change its own structure, returning a constant. Although the function is declared as constexpr, it is not declared as const, which means that if there is any reason to call it a run-time function, it will generate an error if this attempt was made to const S. This affects both versions .

Now a potentially ambiguous return g(S()); Clearly, external g is a function call, but S may not be as clear as it would be if return g(S{}); were written return g(S{}); With {} initializing S, in the future there would be no ambiguity should struct S be extended using the () operator (the structure is almost like a functor). The called constructor is automatically generated now, and there is no operator () to create confusion for the compiler in this version, but modern C ++ 14 should offer clearer alternatives to avoid the "Most Vexing Parse", which is g (S ()).

So, I have to say that on the basis of semantic rules they both fail (not so bad though).

-3
source

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


All Articles