In C++17, this code is illegal:
constexpr int foo(int i) {
return std::integral_constant<int, i>::value;
}
That's because even if foo
can be evaluated at compile-time, the compiler still needs to produce the instructions to execute it at runtime, thus making the template instantiation impossible.
In C++20 we will have consteval
functions, which are required to be evaluated at compile-time, so the runtime constraint should be removed. Does it mean this code will be legal?
consteval int foo(int i) {
return std::integral_constant<int, i>::value;
}
No.
Whatever changes the paper will entail, which is little at this point, it cannot change the fact that a non-template function definition is only typed once. Moreover, if your proposed code would be legal, we could presumably find a way to declare a variable of type
std::integral_constant<int, i>
, which feels very prohibitive in terms of the ODR.The paper also indicates that parameters are not intended to be treated as core constant expressions in one of its examples;
In short, function parameters will never be constant expressions, due to possible typing discrepancy.
No. This is still ill-formed. While
consteval
requires the call itself to be a constant expression, so you know that the argument that producesi
must be a constant expression,foo
itself is still not a template. Template?A slight variation in your example might make this more obvious:
Were this to be valid,
foo(1)
andfoo(2)
would... return different types. This is an entirely different language feature (constexpr function parameters) - because in order for this to work, such functions would really need to behave like templates.It may seem a little unintuitive. After all, if the argument that produced
i
was a constant expression, surelyi
should be usable as one as well? But it's still not - there are no additional exceptions in [expr.const] that permit parameters for immediate functions. An immediate function is still just a function, and its parameters still aren't constant expressions -- in the same way that a normalconstexpr
function's parameters aren't constant expressions.Of course with
int
, we can just rewrite the function to lift the function parameter into a template parameter:And C++20 gives us class types as non-type template parameters, so we can actually do this for many more types than we could before. But there are still plenty of types that we could use as a parameter to an immediate function that we cannot use as a template parameter - so this won't always work (e.g.
std::optional
or, more excitingly in C++20,std::string
).It would seem that this will not be legal in C++20. A good explanation for why this would be problematic to support has already been given in the answers by @Barry and @Columbo (it doesn't really work with the type system). I'll just add what I believe to be the relevant quotes from the standard here that actually make this illegal.
Based on [temp.arg.nontype]/2
A converted constant expression is a constant expression that is implicitly converted to a particular type [expr.const]/7 (here, the type of the template parameter). So your question boils down to the question of whether a variable inside a consteval function is a constant expression. Based on [expr.const]/8
The expression
i
is a glvalue id-expression that is a core constant expression (because its evaluation does not do any of the things listed in [expr.const]/4). However, the entity this core constant expression refers to is not a permitted result of a constant expression [expr.const]/8:The object in question is neither of static storage duration nor is it a temporary object…