Date: Sun, 5 Jan 2025 12:32:51 +0000
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.
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.
Received on 2025-01-05 12:32:53