Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
261 views
in Technique[技术] by (71.8m points)

c++ - constexpr object with mutable member

I came up with this class:

class Point
{
public:
    int X, Y;
    mutable int Z;

    constexpr Point(int x, int y) :X (x), Y(y), Z(0)
    { }

    constexpr int GetX() const
    {
        // Z++; // Wont compile, but following expression is valid!
        return X+Z;
    }

    int GetY() const
    {
        Z++;
        return Y;
    }

    void FoolConst() const
    {
        Z++;
    }
};

And here is usage:

template<int S>
void foo()
{
    std::cout << S << std::endl;
}

int main()
{   
    constexpr Point pt(10, 20);

    pt.FoolConst();

    char arr[pt.GetX()]; // Both compile, but GCC is using extended `new`

    foo<pt.GetX()>(); // GCC fails, VC compiles

    std::cout << sizeof(arr); // 10 (MSVC), 11 (GCC)
    std::cout << pt.GetX();  // 11 (MSVC), 11(GCC)
}

Questions:

  • Why GetX is compiling well with X+Z as return expression (Z is not constexpr).
  • How can I call FoolConst and GetY methods out of constexpr object (pt) ?
  • 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.

For one compiler constexpr GetX is truly constexpr, but for other it is not if X+Z is involved. If I remove +Z and simply return X GCC is okay.

My question is very basic: If object is constexpr how can it call a non-constexpr method?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...