Hello, thanks for bearing with me :)
On Tue, 26 Nov 2024, Jonathan Wakely wrote: > Being a member function makes no difference, but yes, I'm specifically > talking about the case of calling a constexpr function. > > constexpr int bla() { return 2; } > int foo (void) { > const int x = bla(); > int y = bla(); > return x + y; > } > > At -O0 this is one instruction smaller due to the const. Adding const > to y removes another instruction. Hmm hmm. But that is due to how x and y are used, not in how the RHS of their initializers is evaluated (in the above case both initializers are compile-time evaluated also at O0 in gcc). I.e. on -O0 the same difference occurs for const int x = 42; int y = 42; return x + y; ('y' but not 'x' will be stored and reloaded from stack on O0, that's the additional insn, which matches the abstract machine for non-const values). But I was more interested in how the left hand side const qualifier changes semantics for the rhs side in initializers, not how it changes things in further uses of the initialized entity ... > Because in C++ when a const int is initialized by a constant > expression that const int becomes an integral constant: ... and I think that's the crucial thing I was missing: a const int X may or may not be an integral constant, depending on how it's initialized. So it's rather that the kind of the RHS initializer influences the kind of the LHS (as is proper), but only when that LHS is const. Okay, I can live with that :-) ... hmm ... But even then it only has observable effects when that X is used in contexts where an integral constant is required (which wasn't the case in the deque example, perhaps that confused me). > In the bla() example above, the call bla() is a constant expression > when used to initialize a const int, so the compiler is required to > evaluate it at compile time. When used in contexts that doesn't require an integral constant I think a distinction between evaluating at compile time or at run time can't be observed. Obviously all required language rules, diagnostics and constraints have to be observed (and for that the compiler is required to look into the constexpr bla), but I think the ultimate formation of the constant '2' (in our bla() case) can be done arbitrarily complicated at run time, as long as '2' is the result and it's computed in constant time and space. A long winded way of saying that I don't think you can observe a distiction between calling bla() as given or using a literal '2' in these contexts, no matter if x is const, constexpr, or nothing. (let's ignore observation by assembly inspection :) ) > In pure C++11 code I'd make it more explicit and write: > > constexpr int x = blah(); I think I would have been less confused then, but still would have wondered, as 'x' wasn't used in a constexpr-requiring context. I probably would have thought "ahh, someone wanted to make really sure that 'blah' will never be unnoticably rewritten to not be constant-evaluable anymore", not "meh, a optimization hint that shouldn't rightfully be there for a good compiler". Of course, with c++98 using 'const' here seems best now, so thanks for the gcc-help@ lesson! ;-) Ciao, Michael.