Nontype template parameter - c++

I'm having trouble with nontype(int variable) template parameter.
Why can't I pass a constant int variable to a function and let the function instantiate the template?
template<int size>
class MyTemplate
{
// do something with size
};
void run(const int j)
{
MyTemplate<j> b; // not fine
}
void main()
{
const int i = 3;
MyTemplate<i> a; // fine;
run(i); // not fine
}
not fine : compiler says, error: 'j' cannot appear in constant-expression
EDIT
This is what I ended up with.
Maybe someone might use it, someone might suggest better way.
enum PRE_SIZE
{
PRE_SIZE_256 = 256,
PRE_SIZE_512 = 512,
PRE_SIZE_1024 = 1024,
};
template<int size>
class SizedPool : public Singleton< SizedPool<size> >
{
public:
SizedPool()
: mPool(size)
{
}
void* Malloc()
{
return mPool.malloc();
}
void Free(void* memoryPtr)
{
mPool.free(memoryPtr);
}
private:
boost::pool<> mPool;
};
template<int size>
void* SizedPoolMalloc()
{
return SizedPool<size>::GetInstance()->Malloc();
}
template<int size>
void SizedPoolFree(void* memoryPtr)
{
SizedPool<size>::GetInstance()->Free(memoryPtr);
}
void* SizedPoolMalloc(int size)
{
if (size <= PRE_SIZE_256)
return SizedPoolMalloc<PRE_SIZE_256>();
else if (size <= PRE_SIZE_512)
return SizedPoolMalloc<PRE_SIZE_512>();
}
void toRun(const int j)
{
SizedPoolMalloc(j);
}
void Test17()
{
const int i = 3;
toRun(i);
}

Because non-type template parameters require values at compile-time. Remember that templates are a compile-time mechanism; templates do not exist in the final executable. Also remember that functions and the passing of arguments to functions are runtime mechanisms. The value of the j parameter in run() will not be known until the program actually runs and invokes the run() function, well past after the compilation stage.
void run(const int j)
{
// The compiler can't know what j is until the program actually runs!
MyTemplate<j> b;
}
const int i = 3;
run(i);
That's why the compiler complains says "'j' cannot appear in constant-expression".
On the other hand, this is fine because the value of i is known at compile-time.
const int i = 3;
// The compiler knows i has the value 3 at this point,
// so we can actually compile this.
MyTemplate<i> a;
You can pass compile-time values to run-time constructs, but not the other way around.
However, you can have your run() function accept a non-type template parameter the same way your MyTemplate template class accepts a non-type template parameter:
template<int j>
void run()
{
MyTemplate<j> b;
}
const int i = 3;
run<i>();

Basically, C++ has two kinds of constants:
const int a = 5;
MyTemplate<a> foo; // OK
const int b = rand();
MyTemplate<b> foo; // Not OK.
The first example is a compile-time constant. In C++ standard speak, it's an Integral Constant Expression (ICE). The second example is a run-time constant. It has the same C++ type (const int) but it's not an ICE.
Your function void run(const int j) is a run-time constant. You could even pass in user input. Therefore it's not a valid template argument.
The reason for the rule is that the compiler must generate code based on the template argument value. It can't do so if it doesn't have a compile-time constant.

Because j should be known at compile time. In your example it is not.

Related

Uses for cpp struct variables passed in templates

I just want to ask if there are any uses for passing variables in cpp as template arguments
template<int a> struct foo {
int x = a;
};
int main() {
foo<2> bar;
std::cout << bar.x;
}
Something like this compiles, works and cout's 2 but the same thing can be done by doing
struct foo {
int x;
foo(int a) : x(a) {}
};
int main() {
foo bar(2);
std::cout << bar.x;
}
So what is the point of using variables in template arguments? I can also see a big flaw in using the first method: the variable a uses memory and isn't destructed after x is changed, as it would be after the constructor is called in the second example. It might be helpful if you showed some reasonable uses for that.
When you pass a variable through a template argument, it can be used in compile time.
For example, if you need to create a statically sized array in your class, you could use the template argument to pass the size of your array:
template <int TSize>
class Foo {
[...] // Do whatever you need to do with mData.
private:
std::array<int, TSize> mData;
};
There are many uses for constants in template parameters.
Static Sizes
This is how you would start implementing something like a std::array.
template <typename T, size_t SIZE>
struct Array {
T data[SIZE];
}
Template parameters are always usable in a constexpr context, so they can be used as sizes for statically sized arrays.
Providing Compile-Time Parameters to Algorithms
Another use is parametrizing algorithms like in the following code sample.
We have a uint32_t in ARGB order but to store it in a file, we might need to reorder it to BGRA or RGBA. We know the order at compile time, so we could use an ArgbOrder template variable.
enum class ArgbOrder { ARGB, RGBA, BGRA };
struct ChannelOffsets {
unsigned a;
unsigned r;
unsigned g;
unsigned b;
};
// and we can get a constexpr lookup table from this enum
constexpr ChannelOffsets byteShiftAmountsOf(ArgbOrder format)
{
...
}
template <ArgbOrder order>
void encodeArgb(uint32_t argb, uint8_t out[4])
{
// We can generate the shift amounts at compile time.
constexpr detail::ChannelOffsets shifts = shiftAmountsOf(order);
out[0] = static_cast<u8>(argb >> shifts.a);
out[1] = static_cast<u8>(argb >> shifts.r);
out[2] = static_cast<u8>(argb >> shifts.g);
out[3] = static_cast<u8>(argb >> shifts.b);
}
void example() {
encodeArgb<ArgbOrder::BGRA>(12345);
}
In this example, we can select the appropriate lookup table at compile time and have zero runtime cost. All that needs to happen at runtime is 4 shifts.
Feature Toggles
We can use bool template variables to toggle features in our code, like for example:
template <bool handleZeroSpecially>
int div(int x, int y) {
if constexpr (handleZeroSpecially) {
return y == 0 ? 0 : x / y;
}
else {
return x / y;
}
}

Variable length array error with constexpr

I have a class with a member function which declares an array whose size is based off a formula.
template <int SIZE>
class Example{
constexpr int lookup(const int n) const
{
return n * n + n;
}
inline void func()
{
double array[lookup(SIZE)];
}
};
This gives me the vla error. I think it should work because SIZE is resolved at compile time, and lookup is a constexpr. I know the following will work:
template <int SIZE>
class Example{
inline void func()
{
constexpr int sz = SIZE * SIZE + SIZE;
double array[sz];
}
};
I guess I'm just trying to figure out why
EDIT Sorry for the typos, was trying to just write a smaller example and ended up with the missing n and class name.
It's complicated...
First of all, some compilers (see MikeCAT answer and Bill Lynch linked example) can compile the following code (if you give a name to the class and correct lookup() naming n the argument)
inline void func()
{
double array[lookup(SIZE)];
}
because they support a C99 extension that accept the "variable length array" feature.
But this extension isn't standard C++.
You can verify this modifying func() as follows (almost equivalent, in standard C++)
inline void func()
{
constexpr int s = lookup(SIZE);
double array[s];
}
and this can't compile if lookup() is a non-static method
Consider that
lookup(SIZE);
is a short form for
this->lookup(SIZE);
I mean... the use of lookup() involve an object of your class.
The problem is that your func() method is available for both constexpr and non-constexpr objects.
Suppose you have a non-constexpr object: calling func() from it you impose that
constexpr int s = this->lookup(SIZE);
is evaluated compile-time.
That is: you impose that the this pointer (so the object itself) is available compile-time.
This is clearly impossible for run-time created objects, so your code can't compile.
Different if you declare lookup() as a static method: this way, calling lookup() doesn't involve an object of your class so your code can compile.
Class template must have a name.
n is not declared in lookup.
This should work as C++11:
template <int SIZE>
class hoge { // add hoge
constexpr int lookup(const int n) const // add n
{
return n * n + n;
}
inline void func()
{
double array[lookup(SIZE)];
}
};

C++ compile time array size from template function

I'm not sure why the array creation in the function passes but not the one in the class even though array size is a compile time computable value.
template<int N>
int getPow()
{
int power = 1;
while(power < N)
power <<= 1;
return power;
}
template<int N>
class Test
{
private:
int data[getPow<N>()];
};
void testfun()
{
int test[getPow<2>()]; // passes
Test<10> t1; // Fails????
}
As getPow is not constexpr, it cannot be used in places which require constant expression (as C-array size).
int test[getPow<2>()]; // passes
. You unfortunately use VLA extension. It should not pass.
You might solve your issue with:
template <unsigned N>
constexpr unsigned getPow()
{
return 1 << N;
}

Why isn't it a constexpr in this case?

I have a dumb constexpr version of strlen and the compiler accepts it as constexpr in some cases, but in others it does not, here's an example:
template <std::size_t MAX_SIZE>
class FixedString
{
public:
explicit FixedString(const char* str)
{
for(std::size_t i = 0; i < MAX_SIZE; i++)
{
data[i] = str[i];
}
}
char data[MAX_SIZE];
};
constexpr std::size_t constexpr_strlen(const char *str)
{
for(std::size_t i = 0; i < std::numeric_limits<std::size_t>::max(); i++)
{
if(str[i] == '\0')
{
return i;
}
}
return 0;
}
// doesn't compile, compiler says non-type template argument is not a constant expression
auto make_string(const char* str)
{
return FixedString<constexpr_strlen(str)>(str);
}
int main()
{
constexpr bool IS_DEV = true;
// works fine
std::array<int, constexpr_strlen(IS_DEV ? "Development" : "Production")> arr;
// works fine
FixedString<constexpr_strlen(IS_DEV ? "Development" : "Production")> str("Develop");
// doesn't compile, compiler says variable has incomplete type 'void'
auto string = make_string("Not working");
return 1;
}
Why is it that constexpr_strlen is considered constexpr out of the make_string function and in it's not?
For what I can see here, it can be computed at compile time, can't it?
The main problem is that constexpr functions are by definition intended to be callable at compile-time as well as at run-time. Let's start with a simpler example:
constexpr int f(int n) { return n };
int n = 7;
// n could be modified!
f(n); // compiler cannot know which value n has at runtime,
// so the function needs to be executed at runtime as well!
f(7); // well, now right the opposite...
So it's quite simple: The result of a constexpr function is constexpr, too, if and only if all the arguments the function is called with are constexpr themselves (and only then, the function is evaluated at compile-time), otherwise, it will be a runtime value (and the function is evaluated at run-time).
Inside constexpr functions, though, the compiler cannot know if the function is called with constexpr arguments only or not; so function parameters always need to be considered non-constexpr. And here we are...
(Sure, make_string isn't even constexpr, but if constexpr cannot be assumed for parameters of constexpr functions, then even less for normal function parameters...)

Can I perform an optional static_assert if the parameter is known at compile time?

I have a function that only accepts unsigned integers greater than 0 and has a debug assert to check it:
void foo(unsigned int x) {
assert(x > 0);
}
Is it possible to add a static_assert here, so that the code still compiles and also accepts parameters that are not compile time constants?
foo(0); // compilation error
foo(1); // fine
foo(get_x_from_user()); // fine
I know I could make x a template parameter, but I would much prefer to keep this style of call: foo(5); rather than foo<5>();.
I was thinking there might be a way to pull this off with a custom integer type, but I couldn't get very far on that route. Is there a way to do this?
As far as I know, this is not possible without introducing some kind of templating, for example :
template<int T>
class CustomInt
{
public:
static constexpr int value = T;
};
template<int val>
void check(CustomInt<val> /*k*/)
{
static_assert(CustomInt<val>::value > 0, "error!");
check(val);
}
void check(int k)
{
std::cout << "check";
}
int s()
{
volatile int x = 5;
return x;
}
int main() {
check(CustomInt<0>());
check(s());
return 0;
}
This just moves the templating to the custom type though.
If you stick to foo(12) you can't. Because you want the compiler to know the value of a function parameter at compile time. And it's not possible, parameters values are evaluated at runtime. Then it can't be constexpr and then you can not use it in a static_assert.

Categories