Why do I can use non constexpr literal types in constexpr functions(such as reflection) and it can be returned as constexpr, but I can't use such types in template non-type parameters?
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
is not a property of a type. It is a specifier on a variable/function declaration.Objects whose lifetime begins within the evaluation of the constant expression are usable in that constant expression and don't need to be declared
constexpr
.The expression that needs to be a constant expression here is in the first case
The variable
result
insidereflection
lives only during the evaluation of that expression andp
is declaredconstexpr
. Therefore both are usable in the constant expression.In the second case the expression
is required to be a constant expression. This uses
p1
, butp1
is not declaredconstexpr
and its lifetime started before the evaluation of the expression, so it is not usable in the constant expression. More precisely the lvalue-to-rvalue conversion required inxValue()
violates the requirements for a constant expression.