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; }
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.
Arguments are Passed by Value The parameters, in a function call, are the function's arguments. JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations. If a function changes an argument's value, it does not change the parameter's original 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;
consteval int sqrsqr(int n) { return sqr(sqr(n)); // Not a constant-expression at this point, } // but that's okay.
In short, function parameters will never be constant expressions, due to possible typing discrepancy.
Does it mean this code will be legal?
consteval int foo(int i) { return std::integral_constant<int, i>::value; }
No. This is still ill-formed. While consteval
requires the call itself to be a constant expression, so you know that the argument that produces i
must be a constant expression, foo
itself is still not a template. Template?
A slight variation in your example might make this more obvious:
consteval auto foo(int i) { return std::integral_constant<int, i>(); }
Were this to be valid, foo(1)
and foo(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, surely i
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 normal constexpr
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:
template <int i> consteval int foo() { return std::integral_constant<int, i>::value; }
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With