constexpr 表达式和模板参数中的文字类型

literal type in constexpr expression and template parameter

为什么我可以在 constexpr 函数中使用非 constexpr 文字类型(例如反射)并且它可以作为 constexpr 返回,但我不能在模板非类型参数中使用此类类型?

class Point {
    public:
        constexpr Point(double xVal = 0, double yVal = 0) noexcept
        : x(xVal), y(yVal)
        {}

        constexpr double xValue() const noexcept { return x; }
        constexpr double yValue() const noexcept { return y; }

        constexpr void setX(double newX) noexcept { x = newX; }
        constexpr void setY(double newY) noexcept { y = newY; }
    private:
        double x, y;
};

template <long long N>
void F()
{
    std::cout << N << std::endl;
}

constexpr Point reflection(const Point& p) noexcept
{
    Point result;
    result.setX(p.xValue());
    result.setY(p.yValue());
    return result; // returning literal non consexpr type
}
 
int main()
{
    constexpr Point p;
    F<static_cast<long long>(reflection(p).xValue())>(); //result returned from reflection can be used here

    Point p1;
    p1.setX(123);
    F<static_cast<long long>(p1.xValue())>(); //error: the value of ‘p1’ is not usable in a constant expression
}

constexpr 不是类型的 属性。它是 variable/function 声明中的说明符。

生命周期从常量表达式求值开始的对象可用于该常量表达式,不需要声明 constexpr

这里需要是常量表达式的表达式是第一种情况

static_cast<long long>(reflection(p).xValue())

reflection 中的变量 result 仅在该表达式的求值期间存在,并且 p 被声明为 constexpr。因此两者都可用于常量表达式。

在第二种情况下表达式

static_cast<long long>(p1.xValue())

必须是常量表达式。这使用 p1,但 p1 未声明 [​​=12=] 并且其生命周期在表达式求值之前开始,因此它在常量表达式中不可用。更准确地说,xValue() 中要求的 lvalue-to-rvalue 转换违反了常量表达式的要求。