Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will consteval functions allow template parameters dependent on function arguments?

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; } 
like image 385
Annyo Avatar asked May 14 '19 12:05

Annyo


People also ask

Can a template parameter be a function?

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.

Which is a correct example of template parameters?

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.

How are function arguments passed?

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.


2 Answers

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.

like image 106
Columbo Avatar answered Sep 19 '22 08:09

Columbo


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).

like image 28
Barry Avatar answered Sep 19 '22 08:09

Barry