'How to call an operator with constexpr without using temporary variables?

The following sample code illustrates my problem.

constexpr int fact(int N) {
    return N ? N * fact(N - 1) : 1;
}
struct A {
    int d;
    constexpr A operator+(const A& other) const { return A{ fact(d + other.d) }; }
    // overload of many other operators
};

int main() {
    int x;
    cin >> x;                       // run time argument

    constexpr A a{ 2 }, b{ 3 };
    A c{ x };

    A u = a + b + c;                // both + eval at run time
    //constexpr A v = a + b + c;    // doesn't compile because c is not constant
}

What I want to achieve is that the first operator+ is evaluated at compile time and the second operator+ is evaluated at run time.

It is of course possible to break it into

constexpr A tmp = a + b;
A u = tmp + c;

but in my case the whole point of overloading operators is to allow building more complicated formulas in a more intuitive way, so that would make the overloading pointless.

If I declare operator+ as consteval, then it again doesn't compile. And I cannot overload it twice.

Is there a solution?



Solution 1:[1]

You can force the evaluation with (non-type) template parameter or consteval function.

constexpr int fact(int N) {
    return N ? N * fact(N - 1) : 1;
}
struct A {
    int d;
    constexpr A operator+(const A& other) const { return A{ fact(d + other.d) }; }
};

consteval auto value(auto v){return v;}

A foo (int x) {

    constexpr A a{ 2 }, b{ 3 };
    A c{ x };

    A u = value(a+b) + c;
    return u;
}

https://godbolt.org/z/ohf61vebv

Solution 2:[2]

No, at least in gcc and with optimization, here you can see it evaluate at compile time. (the 120)

main:
        mov     eax, 1
        add     edi, 120
        je      .L4
.L3:
        imul    eax, edi
        sub     edi, 1
        jne     .L3
        ret
.L4:
        ret

*To be fair even without constexpr compiler would probably also optimize it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2