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;
}
Related
I'd like to create a type with a compile-time guarantee that instances are one of N possible values. The values are int types. No arithmetic needed.
One possible solution is to use an enum class, but this scales poorly with N.
I think the solution would look most like a fixed range int. I imagine the usage would look something like this, but i'm not too sure how to implement this.Is something like this possible or am I limited to enum classes?
constexpr auto N = 60;
MyType<N> foo(30); // okay
MyType<N> foo(0); // okay
MyType<N> foo(59); // okay
MyType<N> bar(60); // compile error
MyType<N> boo(-1); // compile error
I don't think it's possible to get compile error, however you can limit it using custom class something like this:
#include <stdexcept>
class MyIntger {
public:
MyIntger(int num){
if(num < Min || num > Max){
throw std::runtime_error("Number out of range");
}
value = num;
}
private:
int value;
const static int Min = 0;
const static int Max = 60;
};
int main(){
MyIntger a(5); // OK
MyIntger b(61); // Throws std::runtime_error
}
You can have compile-time ints in C++ (and thus compile-time limit checking), but syntax is not the same as for runtime ints:
#include <type_traits>
template<size_t N>
struct MyInteger
{
// you might have it as T or limit it to size_t
template<typename T, T I>
MyInteger(std::integral_constant<T, I>)
: value(I) { static_assert(I < N); }
size_t value;
};
int main()
{
MyInteger<60> a(std::integral_constant<size_t, 59>()); // ok
MyInteger<60> b(std::integral_constant<size_t, 60>()); // error
}
If you don't like the long name, you can always have a template type alias, e.g.:
template<size_t K>
std::integral_constant<size_t, K> I = {};
int main()
{
MyInteger<60> a(I<59>);
}
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;
}
}
I want to calculate factorial at the compile-time. I found some way to solve the problem, but I want to know if there any another solution for this problem without using enum s. Here the solution using enum s.
#include <iostream>
template <int n>
struct fact
{
enum{value = n*fact<n-1>::value};
};
template<>
struct fact<1>
{
enum{value = 1};
};
int main()
{
std::cout << fact<10>::value;
}
If there is no another solution, please describe why the enum s are must.
While there are alternative notations, It's written that way because more compilers accept that enum-style notation. The language supports const integral-type class members with an inline initialization, but some compilers aren't compliant with the standard in that regard. On compilers that are compliant in this regard, the following works just fine:
#include <iostream>
template <unsigned int n>
struct fact
{
static const unsigned int value = n*fact<n-1>::value;
};
template<>
struct fact<0>
{
static const unsigned int value = 1;
};
int main()
{
std::cout << fact<10>::value << "\n";
}
Replace,
enum{value};
with,
static int const value; // or unsigned int
enums are must because they suppose to be resolved at compile time. Which assures that whatever result you calculated must have been done at compile time. Other such type is static int const (means any integral type).
To illustrate:
enum E {
X = strlen(s); // is an error, because X is a compile time constant
};
Alternatively, you can use static const members:
template <unsigned int n>
struct fact { static const unsigned int value = n * fact<n-1>::value; }
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.
How should I change the code below so that Array<Index> array; is enough and the SIZE is automatically deduced from the enum?
Even if the enum changes, it is guaranteed that it contains SIZE referring to the correct size.
template <typename Enum, int N>
class Array {
public:
int& operator[](Enum index) { return array[index]; }
private:
int array[N];
};
enum Index { X, Y, SIZE };
int main() {
Array<Index, SIZE> array;
array[X] = 1;
return 0;
}
UPDATE: As for "Array<type> means you're creating an array of Type objects" (Jerry) and "the name of class template is a bit misleading" (Nawaz): actually I am creating CustomSqlQueryModel<TableColumns>. The above is just a simplified code, nothing more. Jerry and Nawaz are rigth: this simplified code is unfortunate.
You can write a traits class. This requires a bit of extra work each time you define a new enum type, but no extra work for each occurrence of Array<Index> in user code:
template<class Enum>
struct ArrayTraits;
template<class Enum>
struct Array {
int& operator[](Enum index) { return array[index]; }
private:
int array[ArrayTraits<Enum>::size];
};
enum Index { X, Y, SIZE };
template<>
struct ArrayTraits<Index> {
enum { size = SIZE };
};
int main() {
Array<Index> array;
array[X] = 1;
return 0;
}
One of the advantages of this is you can specialize the traits for external enums you don't control, as long as you know how to get the max size.
As stated, I don't think you can. If, however, you change it to something like:
struct Index {
enum { X, Y, SIZE};
};
Then your template could be something like:
template <class Enum>
class Array {
// ...
private:
int array[Enum::SIZE];
};
...and if the type you pass as Enum doesn't include some positive constant named SIZE,the instantiation won't compile. For the purpose at hand, you'd really kind of prefer that Index was a namespace, but since a namespace isn't a type, I don't think you can use it as a template argument.
I should add, however, that I'm not sure I like this idea at all -- most people are going to think Array<type> means you're creating an array of Type objects, and this is clearly something entirely different from that...
If you want only the size to be template argument, not the type , as from your example it seems that the type of the array would be always int, then why don't you implement this:
template <int size>
class Array {
public:
int& operator[](int index) { return array[index]; }
//Note this addition!
int operator[](int index) const { return array[index]; }
private:
int array[size];
};
int main() {
Array<10> array;
array[0] = 1;
array[1] = 2;
return 0;
}
Note this addition: it's better if you implement const version of operator[] too, so that const Array<> can use it to access the array elements, otherwise your class wouldn't work for const Array<>.