Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why constexpr method can return correctly class members whose value change during execution?

I just discovered that a constexpr method can return correctly the value of a class member that changes during execution. My question is, how is this possible if constexpr methods are supposed to be evaluated completely at compile time?

The example below correctly outputs Value: 0 and then Value: 5. Even more, if I change the a.change(5) to something unpredictible for the compiler (such as a.change(atoi(argv[1])) or a.change(rand() % 10 + 1) it still works. Why? Why does it even compile?

#include <iostream>

class A
{
    public:
        void change(int value) { x = value; }
        int get() const { return x; }
        constexpr int value() const noexcept { return x; }
    private:
        int x{0};
};

int main()
{
    A a;

    std::cout << "Value: "  << a.get() << std::endl;
    a.change(5);
    std::cout << "Value: "  << a.get() << std::endl;
}

Thank you in advance

like image 259
Victor Avatar asked Sep 12 '25 01:09

Victor


2 Answers

In your example you're not even calling the constexpr function, you're calling get, which is not constexpr.

However, constexpr functions can be evaluated at compile time, but also during run time if compile time evaluation is not possible.

If you called value instead of get, it would still work and the function would be evaluated at run time.

In order to force compile time evaluation, you can write

constexpr auto val = a.value();

This will indeed give you an error if compile time evaluation is not possible.

like image 157
Matthias Grün Avatar answered Sep 13 '25 16:09

Matthias Grün


constexpr means that you can use that function in a core constant expression, as long as you have constexpr arguments for it. It can still be used in other contexts.

As it stands, you can't use A::value in a core constant expression, because you have no way of getting a constexpr A. If you instead had

class A
{
    public:
        constexpr A() = default;
        constexpr void change(int value) { x = value; }
        constexpr int get() const noexcept { return x; }
    private:
        int x{1};
};

You could write a function that modified an A at compile time.

constexpr int stuff(A a) {
    a.change(10);
    return a.get();
}

See it on coliru

like image 28
Caleth Avatar answered Sep 13 '25 15:09

Caleth