I have the following template class:
template <unsigned N>
class XArray {
static const int Xdata[N];
};
I want to initialize the static const array for each XArray<N> I used, for example, let XArray<N>::Xdata = {1, 2, 3, ..., N}. How to make it?
you declared a static const int array in your class,so you must define the static member out of the class declaration,just like this:
template<unsigned N>
class XArray
{
public:
static const int array[N];
};
template<unsigned N>
const int XArray<N>::array[N] = {1,2,3,4,5};
But something you must pay attention to is that: when you use this template you must make sure that the "N" bigger than the number of your initialized array;
EDIT:
It seems someone have already provided the solution for your problem in other question, and the answer is quite the same as mine.
Also, for more generic answer, you can check out answers to this question.
Code
If you don't mind using C++11 features, then variadic templates may come handy:
template <unsigned ...Args>
struct XArrayData
{
static const int Values[sizeof...(Args)];
};
template<unsigned N, unsigned ...Args>
struct _XArrayGenerator
{
typedef typename _XArrayGenerator<N - 1, N, Args...>::Xdata Xdata;
};
template<unsigned ...Args>
struct _XArrayGenerator<1, Args...>
{
typedef typename XArrayData<1, Args...> Xdata;
};
template<unsigned N>
struct XArray
{
typedef typename _XArrayGenerator<N>::Xdata Xdata;
};
template <unsigned ...Args>
const int XArrayData<Args...>::Values[sizeof...(Args)] = { Args... };
Explanation
XArray template struct takes the number of array elements as a template parameter (N). In the compilation time, it uses _XArrayGenerator to generate template paremeter list with N consecutive numbers. It begins with the number N, and then recursively uses itself until it reaches 1. At this point, the template parameter list looks like this:
1, 2, ..., N
The last thing to do is to pass these parameters to XArrayData. The last line of the code (definition of the actual array) uses the parameters to initialize the array.
Usage
for (int i = 0; i < 3; ++i)
cout << XArray<3>::Xdata::Values[i] << endl;
Output:
1
2
3
You can initialize as shown below. See inline comments for my explanation.
template <unsigned N>
class XArray {
private:
static const int Xdata[N];
public:
//I added this for illustration purpose
void print()
{
for (int i = 0; i < N; ++i)
{
std::cout << Xdata[i] << std::endl;
}
}
};
//you can initialize like this
//automatic size counting works with static arrays
//here I initialize with 3 elements
//make sure you don't use N < 3 anywhere
template <unsigned N>
const int XArray<N>::Xdata[] = {1,2,3};
int main(void)
{
XArray<3> obj1; //N = 3: This is okay.
XArray<8> obj2; //N > 3: This is okay. Remaining elements will be 0.
XArray<2> obj3; //N < 3: This is also okay.
obj1.print();
obj2.print();
obj3.print(); //but this will give compilation error
return 0;
}
Related
I have the following code:
enum type_kind{unkown=-1,carray, multi_carray};
template<class T>
struct detect_carray{
constexpr static int kind=unkown;
};
template<class T, std::size_t N>
struct detect_carray<T[N]>{
constexpr static int kind=carray;
};
Now, I want to add another specialization for detecting multidimensional arrays in C-style, that is, T[a][b]....
What is the syntax to achieve this? Can I use Variadic templates?
I expect the following behavior:
int main()
{
std::cout<<detect_carray<std::vector<int>>::kind;//-1
std::cout<<detect_carray<int[3]>::kind;//0
std::cout<<detect_carray<double[3][5]>::kind;//1
std::cout<<detect_carray<std::complex<double>[3][5][8][16]>::kind;//1
//Correct out: -1011
}
There's already a trait called std::rank in the standard library so the solution is quite simple:
template <class T>
struct detect_carray {
enum type_kind { unknown = -1, carray, multi_carray };
static constexpr int kind = [] {
switch (std::rank_v<T>) {
case 0: return unknown;
case 1: return carray;
default: return multi_carray;
}
}();
};
Just add a specialization for multidimensional arrays:
template<class T, std::size_t N1, std::size_t N2>
struct detect_carray<T[N1][N2]>{
constexpr static int kind=multi_carray;
};
then
std::cout<<detect_carray<std::vector<int>>::kind;//-1
std::cout<<detect_carray<int[3]>::kind;//0
std::cout<<detect_carray<double[3][5]>::kind;//1
std::cout<<detect_carray<std::complex<double>[3][5][8][16]>::kind;//1
LIVE
BTW: For double[3][5], T will be double (and N1 will be 3 and N2 will be 5). For std::complex<double>[3][5][8][16], T will be std::complex<double> [8][16] (and N1 will be 3 and N2 will be 5).
I understand the concept but i don't know why i require to use non-type template arguments ?
There are many use-cases, so let's look at a couple of situations where they are indispensable:
Fixed sized array or matrix classes, see for example C++11 std::array or boost::array.
A possible implementation of std::begin for arrays, or any code that needs the size of a fixed size C style array, for example:
return the size of an array:
template <typename T, unsigned int N>
unsigned int size(T const (&)[N])
{
return N;
}
They are also extremely useful in template metaprogramming.
A real-world example comes from combining non-type template arguments with template argument deduction to deduce the size of an array:
template <typename T, unsigned int N>
void print_array(T const (&arr)[N]) // both T and N are deduced
{
std::cout << "[";
for (unsigned int i = 0; i != N; ++i)
{
if (i != 0) { std::cout << ", ";
std::cout << arr[i];
}
std::cout << "]";
}
int main()
{
double x[] = { 1.5, -7.125, 0, std::sin(0.5) };
print_array(x);
}
To program at compile-time. Consider the WikiPedia example,
template <int N>
struct Factorial {
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
const int x = Factorial<4>::value; // == 24
const int y = Factorial<0>::value; // == 1
There are a bunch of other examples on the WikiPedia page.
EDIT
As mentioned in the comments, the above example demonstrates what can be done rather than what people use in real projects.
Another example of non type argument is:
template <int N>
struct A
{
// Other fields.
int data[N];
};
Here the length of the data field is parameterised. Different instantiations of this struct can have different lengths of their arrays.
I know that there are easier ways to do it, but
I would like to initialize at compilation time
the map from unrolled index of 2d array to its general format.
I would like to do this without needing to instansiate the array object.
Below I define the map from array[][]->array[].
Now I wonder how to do the opposite: [] -> [][]
without hardcoding the chosen mapping scheme.
I guess that should be possible using metaprogramming and variadic templates.
But I tried using it for the first time just a couple of days ago,
so it takes a while to get used to ;)
header:
template <int dim>
class internal {
static unsigned int table[dim][dim];
static unsigned int x_comp[dim*dim];
static unsigned int y_comp[dim*dim];
};
source:
//1d case:
template <>
unsigned int
internal<1>::table[1][1] = {{0}};
template <>
unsigned int
internal<1>::x_component[1] = {0};
template <>
unsigned int
internal<1>::y_component[1] = {0};
//2d case:
template<>
unsigned int
internal<2>::table[2][2] =
{{0, 1},
{2, 3}
};
// here goes some metaprogramming tricks to initialize
// internal<2>::y_component[2*2] = ...
// internal<2>::x_component[2*2] = ...
// based on mapping above, i.e. table[2][2];
// that is:
// x_table = { 0, 0, 1, 1 }
// y_table = { 0, 1, 0, 1 }
//
// so that :
//
// index == table[i][j]
// i == x_comp[index]
// j == y_comp[index]
EDIT1:
or just tell me that it's not possible and I hard-code everything or use
integer division to relate the two index representations.
EDIT2:
i would prefer to stick with definition of arbitrary arrays.
Of course one can do without, as in answer below using integer division.
Those arrays can be really arbitrary, for example:
template<>
unsigned int
internal<2>::table[2][2] =
{{3, 0},
{2, 1}
};
Using arrays:
Given a table with unique entries from 0 to dim^2-1, you can write constexpr lookup functions for the i and j of a given table entry:
constexpr unsigned get_x_comp(unsigned index, unsigned i=0, unsigned j=0)
{ return table[i][j] == index ? i : get_x_comp(index, ((j+1)%dim ? i : i+1), (j+1)%dim); }
constexpr unsigned get_y_comp(unsigned index, unsigned i=0, unsigned j=0)
{ return table[i][j] == index ? j : get_y_comp(index, ((j+1)%dim ? i : i+1), (j+1)%dim); }
These will recursively call themselves, iterating through the table and looking for index. Recursion will eventually end when the given index is found and i/j of that index is returned.
Combine that with the C++14 std::integer_sequence mentioned by Jonathan to initialize the arrays:
template<unsigned... I>
constexpr auto make_x_comp(std::integer_sequence<unsigned, I...>) -> std::array<unsigned, sizeof...(I)> { return {get_x_comp(I)...}; }
Using metafunctions instead of arrays:
In some cicumstances, one might not even need arrays. I assume you want to the table to contain consecutive indices from 0 to dim^2-1. If that's the case, table, x_comp and y_comp are only simple compiletime functions with the following attributes:
table(i,j) := i*dim + j
x_comp(index) := index / dim (integer division)
y_comp(index) := index % dim
Depending on if you have C++11 features available, the implementation will be different, but both times without arrays.
Note: the following implementations will assume that the numbers stored in table are consecutive from 0 to dim^2-1. If that is not the case, you'll have to roll your own appropiate function for table and use the above get_x_comp and get_y_comp implementatio
C++11:
template <unsigned dim> //use unsigned to avoid negative numbers!
struct internal {
static constexpr unsigned table(unsigned i, unsigned j) { return i*dim+j; }
static constexpr unsigned x_comp(unsigned index) { return index/dim; }
static constexpr unsigned y_comp(unsigned index) { return index%dim; }
};
You can call these functions like normal functions anywhere, especially anywhere you need compiletime constants. Example: int a[internal<5>::table(2,4)];
C++03:
template <unsigned dim> //use unsigned to avoid negative numbers!
struct internal {
template<unsigned i, unsigned j>
struct table{ static const unsigned value = i*dim+j; };
template<unsigned index>
struct x_comp{ static const unsigned value = index/dim; };
template<unsigned index>
struct y_comp{ static const unsigned value = index%dim; };
};
Using these metafunctions is a bit more clumsy than in C++11, but works as usual with template metafunctions. Same example as above: int a[internal<5>::table<2,4>::value];
Note: This time you can put the (meta-)functions in the header, since they are not non-integral static member variables any more. Also you do not need to restrict the template to small dimensions, since everything will be calculated well for dimensions less than sqrt(numeric_limits<unsigned>::max()).
I'm sorry if I'm not answering the question directly (or at all), but I don't really understand what you're asking. I think what you're saying is that you want to initialize at compilation time a way to have an array of size N x M represented as a 1D array?
I've included code that allows you to allocate non-square dimensions. I've built this in "easy" C++ so if you're just getting into templates it's not so difficult to follow.
Is it possible to do something like this?
template <typename T, typename std::size_t N, typename std::size_t M = 1>
class Array {
T* data;
public:
Array<T, N, M>() : data(new T[N * M]) {
T temp = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
data[i * M + j] = temp++;
}
}
}
/* methods and stuff
}
Where M is the column number, so you'd use this like:
int main(void) {
Array<float, 10, 10> myArray;
return 0;
}
Remember to call delete in the destructor.
Edit: I didn't understand the rule for populating x_comp and y_comp when I wrote this, now that I see that part of the question this answer is not really relevant, because I was incorrectly assuming table only contained consecutive integers. The answer is left here anyway because Arne's (much better) answer refers to it.
I would replace the arrays with std::array and use the C++14 integer_sequence utility:
template <int dim>
struct internal {
static std::array<std::array<unsigned, dim>, dim> table;
static std::array<unsigned, dim*dim> x_comp;
static std::array<unsigned, dim*dim> y_comp;
};
template<unsigned Origin, unsigned... I>
constexpr std::array<unsigned, sizeof...(I)>
make_1d_array_impl(std::integer_sequence<unsigned, I...>)
{
return { { I + Origin ... } };
}
template<int N>
constexpr std::array<unsigned, N*N>
make_1d_array()
{
return make_1d_array_impl<0>(std::make_integer_sequence<unsigned, N*N>{});
}
template<unsigned... I>
constexpr std::array<std::array<unsigned, sizeof...(I)>, sizeof...(I)>
make_2d_array_impl(std::integer_sequence<unsigned, I...> seq)
{
return { { make_1d_array_impl<I*sizeof...(I)>(seq) ... } };
}
template<int N>
constexpr std::array<std::array<unsigned, N>, N>
make_2d_array()
{
return make_2d_array_impl(std::make_integer_sequence<unsigned, N>{});
}
template<int dim>
std::array<std::array<unsigned, dim>, dim> internal<dim>::table = make_2d_array<dim>();
That fills the table array correctly. I'll have to think about it a bit more to populate x_comp and y_comp as you want, but it's doable.
You can find an C++11 implementation of integer_sequence at https://gitlab.com/redistd/integer_seq/blob/master/integer_seq.h
I understand the concept but i don't know why i require to use non-type template arguments ?
There are many use-cases, so let's look at a couple of situations where they are indispensable:
Fixed sized array or matrix classes, see for example C++11 std::array or boost::array.
A possible implementation of std::begin for arrays, or any code that needs the size of a fixed size C style array, for example:
return the size of an array:
template <typename T, unsigned int N>
unsigned int size(T const (&)[N])
{
return N;
}
They are also extremely useful in template metaprogramming.
A real-world example comes from combining non-type template arguments with template argument deduction to deduce the size of an array:
template <typename T, unsigned int N>
void print_array(T const (&arr)[N]) // both T and N are deduced
{
std::cout << "[";
for (unsigned int i = 0; i != N; ++i)
{
if (i != 0) { std::cout << ", ";
std::cout << arr[i];
}
std::cout << "]";
}
int main()
{
double x[] = { 1.5, -7.125, 0, std::sin(0.5) };
print_array(x);
}
To program at compile-time. Consider the WikiPedia example,
template <int N>
struct Factorial {
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
const int x = Factorial<4>::value; // == 24
const int y = Factorial<0>::value; // == 1
There are a bunch of other examples on the WikiPedia page.
EDIT
As mentioned in the comments, the above example demonstrates what can be done rather than what people use in real projects.
Another example of non type argument is:
template <int N>
struct A
{
// Other fields.
int data[N];
};
Here the length of the data field is parameterised. Different instantiations of this struct can have different lengths of their arrays.
I need to pass an array as a template type. How can achieve it. For example, I want something like this.
Fifo<array, Q_SIZE> f; // This is a queue of arrays (to avoid false sharing)
What should I put in place of array? Assume I need an array of int. Also note that I don't want std::vector or a pointer to an array. I want the whole basic array, something equivalent of say int array[32].
Try this:
Fifo<int[32], Q_SIZE> f;
Like this:
#include <iostream>
template <class T, int N>
struct Fifo {
T t;
};
int main () {
const int Q_SIZE = 32;
Fifo<int[32],Q_SIZE> f;
std::cout << sizeof f << "\n";
}
If you want to pass array type when creating queue you can write
template <typename Array>
struct Fifo;
template <typename T, int size>
struct Fifo<T[size]>
{
};
or just
template <typename Array>
struct Fifo
{
};
and use it like
int main()
{
Fifo<int[10]> fa;
}
Then, you should understand, that int[10] is completely different type from int[11], and once you created Fifo<int[10]> you cannot store here arrays of size 11 or 9 anymore.
The std::end function in C++ 11 has an overload for array types that nicely demonstrate this.
Here's a possible implementation of it:
template< class T, std::size_t N >
T* end(T(&array)[N]) {
return array + N;
}
If you need an object that wraps an array, a templated factory function will help creating it:
template< class T, std::size_t N >
struct fifo {
T(&array)[N];
};
template< class T, std::size_t N >
fifo<T,N> make_fifo(T(&array)[N]) {
return Fifo<T,N>{ array };
}
int main() {
int arr[] = { 1,2,3,4,5 };
// Create object from array using template argument deduction
auto fifo = make_fifo(arr);
}
Well I've found a solution. I can wrap the array in a structure, such as below.
typedef struct
{
int array[32];
} my_array;
Then I can use it as follows.
Fifo<my_array, Q_SIZE> f;