A constant expression cannot access a mutable sub-object. This is in [expr.const]/2:
A conditional-expression e
is a core constant expression unless the evaluation of e, following the rules of the
abstract machine (1.9), would evaluate one of the following expressions: [...]
- an lvalue-to-rvalue conversion (4.1) unless it is applied to [...]
- a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers
to a non-mutable sub-object of such an object [...]
So GetX
cannot be used within a constant expression, e.g. as a template parameter foo<pt.GetX()>()
.
In answer to your specific questions:
- Why GetX is compiling well with X+Y as return expression (Z is not constexpr).
A compiler is not required to check that constexpr functions (incl. member functions) are fully valid when they are defined, only when they are used. It does have to check a few things, like not using goto
[dcl.constexpr]/3, but it doesn't have to check which objects the definition accesses. This is because whether the constexpr function can be used within a constant expression can depend on the values of its arguments.
In fact, because GetX
unconditionally accesses Z
, your program strictly has undefined behavior per [dcl.constexpr]/5:
For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting
constexpr constructor, if no argument values exist such that an invocation of the function or constructor
could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no
diagnostic required.
"Ill-formed; no diagnostic required" is another way of saying that the behavior of your program is undefined.
- How can I call FoolConst and GetY methods out of constexpr object (pt) ?
That's absolutely fine; an object declared constexpr
is just a const
object from the point of view of non-constexpr
member functions of that object.
- The behaviour of GetX in main is different in compilers. MSVC compiles fine with a int as template argument, while GCC (IdeOne) won't compile it.
Unfortunately, both compilers are correct; your program has undefined behavior in the definition of GetX
, so there is no single correct behavior for the compiler.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…