Am 14.03.2012 21:33, schrieb Andrzej Krzemieński:
> Hi,
> This is my literal type:
>
> struct C
> {
> double m;
> constexpr C( double m ) : m{m} {};
> constexpr double get() const { return m; };
> };
>
> Therefore the following code works:
>
> constexpr C c = C{5.};
> constexpr double k = c.get();
Correct.
> But the following does not:
>
> const C cc = C{5.}; // but not constexpr
> constexpr double kk = cc.get();
>
> Why is this so? Object cc is subject to const initialization anyway. It is possible to make it work only by a seemingly irrelevant change in declaration (add constexpr). What was the reason for disallowing this "implicit generation of compile-time constants"?
This was a deliberate decision. Variables declared with const share
different responsibilities, while constexpr is much clearer. const means
(a) "cannot modify", it can also mean (b) constant initialization, *and*
it can mean (c) that the variable can be used within constant expressions.
const int n1 = 12;
satisfies all three requirements, while
int f();
const int n2 = f();
only the first. One other interesting corner case is
#include<mutex>
std::mutex m;
satisfies only the second (I'm ignoring here address-constant expression
within this discussion, which is a very special family of constant
expressions).
C++11 kept the very restricted use-case of const variables useable in
constant expressions which is the special bullet in 5.19 (emphasize mine):
"a non-volatile glvalue of integral or enumeration type that refers to a
non-volatile const object with a preceding initialization, **initialized
with a constant expression**"
but didn't invest the efforts to extend this for other literal types,
because the existing rules were surprising and not easy to understand.
The much simpler and more general bullet
"a non-volatile glvalue of literal type that refers to a non-volatile
object defined with constexpr, or that refers to a sub-object of such an
object"
rules basically all the rest.
HTH& Greetings from Bremen,
Daniel Krügler