Variable length array error with constexpr - c++

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)];
}
};

Related

Understanding CPP specific Class declaration and resulting error

My CPP understanding is not good enough to understand the following Class declaration
#define Default_n_datapoints 10
class MeanAngle {
public:
MeanAngle(std::size_t a_nDataPoints = Default_n_datapoints) :
NDATAPOINTS (a_nDataPoints) {};
virtual ~MeanAngle();
virtual void AddSample(const float a_fSample);
virtual float GetAverage() const;
protected:
const std::size_t NDATAPOINTS;
private:
float ring[NDATAPOINTS];
uint8_t i;
};
and in particular: If NDATAPOINTS is const, why can't I use it dimensioning ring[]? ring[NDATAPOINTS] gives me an error:
A non-static member reference must be relative to a specific object
How should I correct the declaration? What I want is that the initialisation parameter a_nDataPoints to be used as dimension in the ring buffer.
A specified array size must be a compile-time constant. That is, its value must be known at compile time. If you pretend that you are a C++ compiler, yourself, look at this code, and attempt to figure out what actual, integer, value NDATAPOINTS is, you will fall far short of your lofty goals.
The only thing that const gives you is that a const value is a run-time constant. It never changes once it exists. That's not the same thing as a compile-time constant. A compile-time constant would be a constexpr.
If you will always use this class with compile-time constant as argument, then you can make it template:
#include <cstdint>
static constexpr std::size_t Default_n_datapoints = 10ul;
template<std::size_t N = Default_n_datapoints>
class MeanAngle {
public:
MeanAngle() {};
virtual ~MeanAngle();
virtual void AddSample(const float a_fSample);
virtual float GetAverage() const;
protected:
const std::size_t NDATAPOINTS = N;
private:
float ring[N];
uint8_t i;
};
You can then use it like that:
MeanAngle<5> a;
MeanAngle<> b; // Default size will be used

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;
}
}

Using "constexpr" to use string literal for template parameter

I have written some code to cast const char* to int by using constexpr and thus I can use a const char* as a template argument. Here is the code:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}
private:
const char* string;
std::size_t size;
};
// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};
int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}
int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}
In this example code, type of out is OUT<1494474505> and type of out2 is OUT<106227495>. Magic behind this code is conststr::hash() it is a constexpr recursion that uses FNV Hash function. And thus it creates an integral hash for const char* which is hopefully a unique one.
I have some questions about this method:
Is this a safe approach to use? Or can this approach be an evil in a specific use?
Can you write a better hash function that creates different integer for each string without being limited to a number of chars? (in my method, the length is long enough)
Can you write a code that implicitly casts const char* to int constexpr via conststr and thus we will not need aesthetically ugly (and also time consumer) _const user-defined string literal? For example OUT<"String"> will be legal (and cast "String" to integer).
Any help will be appreciated, thanks a lot.
Although your method is very interesting, it is not really a way to pass a string literal as a template argument. In fact, it is a generator of template argument based on string literal, which is not the same: you cannot retrieve string from hashed_string... It kinda defeats the whole interest of string literals in templates.
EDIT : the following was right when the hash used was the weighted sum of the letters, which is not the case after the edit of the OP.
You can also have problems with your hash function, as stated by mitchnull's answer. This may be another big problem with your method, the collisions. For example:
// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;
As far as I know, you cannot pass a string literal in a template argument straightforwardly in the current standard. However, you can "fake" it. Here's what I use in general:
struct string_holder //
{ // All of this can be heavily optimized by
static const char* asString() // the compiler. It is also easy to generate
{ // with a macro.
return "Hello world!"; //
} //
}; //
Then, I pass the "fake string literal" via a type argument:
template<typename str>
struct out
{
out()
{
std::cout << str::asString() << "\n";
}
};
EDIT2: you said in the comments you used this to distinguish between several specializations of a class template. The method you showed is valid for that, but you can also use tags:
// tags
struct myTag {};
struct Long {};
struct Float {};
// class template
template<typename tag>
struct Integer
{
// ...
};
template<> struct Integer<Long> { /* ... */ };
// use
Integer<Long> ...; // those are 2
Integer<Float> ...; // different types
Here is the pattern that I am using for template const string parameters.
class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};
see :
https://stackoverflow.com/a/18031951/782168

How to declare a constant array in class with constant class variable?

How to declare a constant array in class with constant class variable? Is it possible.
I don't want dynamic array.
I mean something like this:
class test
{
const int size;
int array[size];
public:
test():size(50)
{}
}
int main()
{
test t(500);
return 0;
}
the above code gives errors
No, it's not possible: As long as size is a dynamic variable, array[size] cannot possibly be implemented as a static array.
If you like, think about it this way: sizeof(test) must be known at compile time (e.g. consider arrays of test). But sizeof(test) == sizeof(int) * (1 + size) in your hypothetical example, which isn't a compile-time known value!
You can make size into a template parameter; that's about the only solution:
template <unsigned int N>
class Test
{
int array[N];
static const unsigned int size = N; // unnecessary really
public:
// ...
};
Usage: Test<50> x;
Note that now we have sizeof(Test<N>) == sizeof(int) * (1 + N), which is in fact a compile-time known value, because for each N, Test<N> is a distinct type.
You mean a fixed sized array? You could use std::array like this:
#include <array>
class test
{
static const size_t s_size = 50;
std::array<int, s_size> m_array;
public:
test()
{
}
};
Or if you want to support different sizes you need to resort to a class template like this:
#include <array>
template <size_t SIZE>
class test
{
std::array<int, SIZE> m_array;
public:
test()
{
}
};
std:array has the added benefit of keeping the size information along with the member (unlike arrays which decay to pointers) and is compatible with the standard library algorithms.
There is also a version that Boost offers (boost::array) which is similar.
Your code yields an error because compiler needs to know the size of data type of each member. When you write int arr[N] type of member arr is "an array of N integers" where N must be known number in compile time.
One solution is using enum:
class test
{
enum
{
size = 50
};
int arr[size];
public:
test() {}
};
Another is declaring size as static const member of class:
class test
{
static const int size = 50;
int arr[size];
public:
test(){}
};
Note that in-class initialization is allowed only for static class integers! For other types you need to initialize them in code file.

Nontype template parameter

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.