Skip to main content
added 32 characters in body
Source Link
ecatmur
  • 158.3k
  • 28
  • 311
  • 387

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).

  • 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. (ItIt 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:

How can I call FoolConst and GetY methods out ofFor a non-template, non-defaulted constexpr objectfunction 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 (pt5.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.

  • 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.

MSVC is defective; GCCUnfortunately, both compilers are correct; your program has undefined behavior in the definition of GetX, so there is no single correct behavior for the compiler.

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.)

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.

MSVC is defective; GCC is correct.

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.

added 32 characters in body
Source Link
ecatmur
  • 158.3k
  • 28
  • 311
  • 387

A constant expression cannot access a mutable sub-object. This is in [expr.const][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.)

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.

MSVC is defective; GCC is correct.

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 valid when they are defined, only when they are used. (It does have to check a few things, like not using goto, but it doesn't have to check which objects the definition accesses.)

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.

MSVC is defective; GCC is correct.

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.)

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.

MSVC is defective; GCC is correct.

Source Link
ecatmur
  • 158.3k
  • 28
  • 311
  • 387

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 valid when they are defined, only when they are used. (It does have to check a few things, like not using goto, but it doesn't have to check which objects the definition accesses.)

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.

MSVC is defective; GCC is correct.