Consider the following class used to calculate at compile time the factorial of a number:
template<unsigned n>
struct Factorial {
static constexpr unsigned value = n * Factorial<n-1u>::value;
};
template<>
struct Factorial<0> {
static constexpr unsigned value = 1u;
};
Now let's try to double it:
consteval unsigned DoubleFactorial(unsigned const arg)
{
return 2u * Factorial<arg>::value;
}
This won't compile because 'arg' isn't a constant expression . . .even though it's inside a consteval function and its value is known at compile time.
It might be a lot of work to rewrite the standard to specify that the arguments to a function are constant expressions if the function is consteval, but maybe it would be a lot less work to add a new feature that allows us to explicitly specify that a value is a constant expression, perhaps something like:
consteval unsigned DoubleFactorial(unsigned const arg)
{
[constexpr arg : carg];
return 2u * Factorial<carg>::value;
}
The line:
[constexpr arg : carg];
takes the value of 'arg' which is known at compile time, and turns it into a constant expression called 'carg' which can be used as a template parameter.
A more complex use would be something like:
constexpr unsigned DoubleFactorial(unsigned arg)
{
if consteval
{
[constexpr arg : carg];
return 2u * Factorial<carg>::value;
}
else
{
unsigned retval = 2u;
while ( arg ) retval *= arg--;
return arg;
}
}
I realise that this feature isn't very pretty and is more of an improvisation to get around pre-existing language limitations, but it's nowhere near as bad as forwarding references.