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
}
CodePudding user response:
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
static_cast<long long>(reflection(p).xValue())
The variable result
inside reflection
lives only during the evaluation of that expression and p
is declared constexpr
. Therefore both are usable in the constant expression.
In the second case the expression
static_cast<long long>(p1.xValue())
is required to be a constant expression. This uses p1
, but p1
is not declared constexpr
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 in xValue()
violates the requirements for a constant expression.