如何在不使用临时变量的情况下使用 constexpr 调用运算符?

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

下面的示例代码说明了我的问题。

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
}

我想要实现的是第一个 operator+ 在编译时求值,第二个 operator+ 在 运行 时求值。

当然可以分解成

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

但在我的例子中,重载运算符的全部意义在于允许以更直观的方式构建更复杂的公式,这样会使重载毫无意义。

如果我将 operator+ 声明为 consteval,那么它又不会编译。而且我不能重载它两次。

有解决办法吗?

不,至少在 gcc 中并经过优化,here 您可以看到它在编译时求值。 (120)

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

*公平地说,即使没有 constexpr 编译器也可能会对其进行优化。

您可以使用 (non-type) 模板参数或 consteval 函数强制计算。

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