How to detect C-style multidimensional arrays in templates specialization? - c++

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).

Related

Initialize POD with two arrays using a factory function in C++11

I need to POD-initialize a struct of multiple arrays from a factory function. How do I forward its parameters to the brace-init list that is required to create the POD-struct (C++11)? I get this error:
<source>: In instantiation of 'constexpr generic_option<N, K> create_option(const int (&&)[N], const int (&&)[K]) [with long unsigned int N = 2; long unsigned int K = 2]':
<source>:209:32: required from here
<source>:204:48: error: array must be initialized with a brace-enclosed initializer
204 | return generic_option<N, K>{to_wait, to_set};
| ^
<source>:204:48: error: array must be initialized with a brace-enclosed initializer
<source>:205:1: error: body of 'constexpr' function 'constexpr generic_option<N, K> create_option(const int (&&)[N], const int (&&)[K]) [with long unsigned int N = 2; long unsigned int K = 2]' not a return-statement
205 | }
| ^
My code:
template <size_t N, size_t K>
struct generic_option
{
int to_wait_[N];
int to_set_[K];
};
template <size_t N, size_t K>
constexpr generic_option<N, K> create_option(const int (&&to_wait)[N], const int (&&to_set)[K]) {
return generic_option<N, K>{to_wait, to_set};
}
int main()
{
create_option({1,4}, {2,3});
}
The reason for this post is that I can find information on how to initialize a struct of arrays with brace initializers using literals. But I can't seem to find a resource that states how to initialize them using compile time variables such as the ones passed to the factory function.
I'm afraid you will need to find another way to do that.
As the compiler tells you, when initialising a class member that is raw C array, you must specify each element individually within a pair of {}, even if the array is a prvalue.
Minimum reproducible example is probably this:
struct some_struct
{
int array[2];
};
int(&& array)[2] = {0, 1};
//some_struct s {array}; //Won't compile
some_struct s2 {{array[0], array[1]}}; //Compiles
I suggest you use std::array instead of the raw C-style arrays.
template <std::size_t N, std::size_t K>
struct generic_option
{
std::array<int, N> to_wait_;
std::array<int, K> to_set_;
};
template <size_t N, size_t K>
constexpr generic_option<N, K> create_option(std::array<int, N>&& w, std::array<int, N>&& s)
{
return generic_option<N, K>{w, s};
}
Note that std::array is also POD (fulfills std::is_standard_layout_v and std::is_trivial_v), but because it has an additional member (its size), sizeof(generic_option) will also increase (but not by much).
You will also have to specify the template arguments manually here because no guidelines are available in the context (but since you're in C++11, you would probably have to do that anyway).
In C++17, you have an elegant a way (at least I find it elegant) to do that using by passing std::tuple&& as argument instead and creating the arrays with std::apply. But that solution will still require using std::array. Note that you could implement something like std::apply yourself, see the answers here.
template <typename... w_t, typename... s_t>
constexpr generic_option<
std::tuple_size_v<std::tuple<int, w_t...>>,
std::tuple_size_v<std::tuple<int, s_t...>>
>
create_option(std::tuple<int, w_t...>&& to_wait, std::tuple<int, s_t...>&& to_set)
{
constexpr std::size_t N = std::tuple_size_v<std::tuple<int, w_t...>>;
constexpr std::size_t K = std::tuple_size_v<std::tuple<int, s_t...>>;
constexpr auto create_wait = [](auto&& ... x){ return std::array<int, N>{std::forward<decltype(x)>(x) ... }; };
constexpr auto create_set = [](auto&& ... x){ return std::array<int, K>{std::forward<decltype(x)>(x) ... }; };
return generic_option<N, K>
{
std::apply(create_wait, std::forward<decltype(to_wait)>(to_wait)),
std::apply(create_set, std::forward<decltype(to_set)>(to_set)),
};
}
You might be able to use fold expressions instead (still in C++17), but I cannot figure that out.

Programmatic initialization of a long array at compile or initialization time

Here is a code snippet illustrating my question:
const float D = 0.1F;
const float A[4] = {sin(0*D), sin(1*D), sin(2*D), sin(3*D)};
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time, i.e. without having to write initialization function and call it somewhere in my program?
You could initialize A during dynamic initialization time as follows:
const float *init_a(float x_)
{
static float data[4];
for(unsigned i=0; i<4; ++i)
data[i]=sin(i*x_);
return data;
}
const float D=0.1f;
const float *A=init_a(D);
You may use code generator to generate initialization code. That is, write program that will write your initialization code for you. You may actually calculate values at generation-time.
Remember that C++ allows placing , after last element. It's also isn't necessary to specify array size. These two things should ease writing of generator.
This simple python code should work well:
from math import sin
print('const float A[', N, '] = {')
for i in range(N):
print('\t', sin(i*D), ',', sep='')
print('};')
Ok I just realized this doesn't actually answer the question, because it specifies "without having to write initialization function and call it somewhere in my program?" But I can't think of a convenient alternative.
template<size_t N>
std::array<float, N> GetLookupTable(float d)
{
std::array<float, N> table;
// .. populate table here
return table;
}
// a global somewhere
(static?) const auto Table_10x5 = GetLookupTable<10>(5.0f);
This first part is obsolete in C++14, but not long:
template<unsigned...>struct indexes { using type=indexes; };
template<unsigned Max, unsigned...Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
template<unsigned Max>using make_indexes_t=typename make_indexes<Max>::type;
this is some template meta programming that lets us create and pass around bundles of indexes.
Then some code to generate the array:
namespace details {
template<std::size_t N, unsigned...Is>
std::array<float, N> poly_sin(float src, indexes<Is...>) {
return { (Is*sin(src))... };
}
}
template<std::size_t N>
std::array<float, N> poly_sin(float src) {
return details::poly_sin<N>( src, make_indexes_t<N>{} );
}
The first method takes indexes<Is...> and we plan that Is... is 0, 1, 2, ..., N-1. It then expands the parameter pack into a std::array of the right size.
make_indexes_t<N>{} expands (at compile time) to indexes<0, 1, 2, ..., N-1>{}, which is then passed to details::poly_sin, which then can deduce the Is... and use them within itself.
And point of use:
const float D = 0.1F;
const auto A = poly_sin<4>(D);
if you had a constexpr sin function, you could even make poly_sin a constexpr function and have it basically guaranteed to be evaluated at compile time.
If this is the case, make D constexpr and same with the two poly_sin functions.
As written, this occurs at dynamic initialization time.
While it appears that the array is copied twice, RVO elision means that any decent compiler will directly construct it in A.
If you want to be able to do this in general, first start with the above indexes code. Then add this:
template<class Sig>using result_of_t=typename std::result_of<Sig>::type;
namespace details {
template<std::size_t N, class F, unsigned... Is>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f, indexes<Is...> ) {
return { f( Is )... };
}
}
template<std::size_t N, class F>
std::array< result_of_t< F(unsigned) >, N >
make_array( F&& f ) {
return details::make_array( std::forward<F>(f), make_indexes_t<N>{} );
}
const auto A = make_array<4>( [](unsigned i){ return float(i*sin(D)); } );
which uses a lambda to pass in the code that is repeated to build the array. Sadly, lambdas are not by default constexpr so you cannot do it at compile time.
You could either use boost.preprocessor and in particular the BOOST_PP_ENUM macro, like the example below:
#include <iostream>
#include <cmath>
#include <boost/preprocessor/repetition/enum.hpp>
#define SIZE 4
#define D 0.1
#define ORDER(z, n, text) std::sin(n * D)
double const A[SIZE] = { BOOST_PP_ENUM(SIZE, ORDER, ~) };
int main() {
for(auto i : A) std::cout << i << std::endl;
}
Or, you could use std::array instead of raw arrays, and via use of template meta-programming to generate a std::array at compile time. like the example below:
template<typename T, typename F, int SIZE, int... N>
constexpr std::array<T, SIZE>
genarray(F f) {
return std::array<T, SIZE>{{ f(N)... }};
}
template<typename T, typename F, int SIZE, int...> struct recursive_gen;
template<typename T, typename F, int SIZE, int... Args>
struct recursive_gen<T, F, SIZE, 0, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return genarray<T, F, SIZE, 0, Args...>(f);
}
};
template<typename T, typename F, int SIZE, int N, int... Args>
struct recursive_gen<T, F, SIZE, N, Args...> {
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, N - 1, N, Args...>::generate(f);
}
};
template<typename T, int SIZE>
struct array_generator {
template<typename F>
static constexpr std::array<T, SIZE> generate(F f) {
return recursive_gen<T, F, SIZE, SIZE - 1>::generate(f);
}
};
std::array<double, 4> const A = array_generator<double, 4>::generate([](int i) { return std::sin(0.1 * i);});
std::array<double, 4> const B = array_generator<double, 4>::generate([](int i) { return std::cos(0.1 * i);});
constexpr int fun(int i) { return 2 * i; }
constexpr std::array<int, 4> const C = array_generator<int, 4>::generate(fun); // generation during compile time
LIVE DEMO
Note however, that in order for generation to take place at compile time input function in array_generator must be constexpr. This is not the case for trigonometric functions (i.e., they are not constexpr). Thus initialization of arrays A and B will take place at initialization time, whereas generation of array C will take place at compile time.
Imagine that global array A is much longer and you don't want to do all of this repetitive typing. Is there a shorter way to initialize array A at compile or initialization time
Create a generator and pass it through std::generate_n() (or plain std::generate()).
#include <algorithm>
#include <array>
#include <cmath>
template <typename Value_t>
struct SinGenerator{
SinGenerator(std::size_t start = 0, Value_t counter_scalar = 1)
: index{start},
scalar{counter_scalar} {
}
Value_t operator()() {
return sin(index++ * scalar);
}
std::size_t index;
Value_t scalar;
};
template <typename Value_t, std::size_t Size>
std::array<Value_t, Size> init_table(const std::size_t start,
const Value_t counter_scalar) {
std::array<Value_t, Size> arr;
SinGenerator<Value_t> gen(start, counter_scalar);
std::generate(arr.begin(), arr.end(), gen);
return arr;
}
const auto kSinTable(init_table<float, 10>(0, 0.1f));
In case you A array will always stays the same and is very big, you can always write a short script, which calculates every value in array and output could be used in source code to have static initialization.
In case formula is simple, even MS Excel could be used to generate that kind of static initialization data.

C++ static const array initialization in template class

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

Meta-programming problem with Enums

Atm i have sth like that:
template<int n>
struct Pow
{
enum{val= Pow<n-1>::val<<1};
};
template<>
struct Pow<0>{
enum{val =1};
};
I can acess data like Pow<30>::val. It's good but i want do like this
int main()
{
Pow<30>::val;
and then use variable to
access all of value <0,30>
I knew that i can use array and dynamic programming but can i do that in this way?
Sorry for English.
Using C++0x variadic templates:
template<int... Indices>
struct powers {
static const int value[sizeof...(Indices)];
typedef powers<Indices..., sizeof...(Indices)> next;
};
template<int... Indices>
const int powers<Indices...>::value[sizeof...(Indices)] = { Pow<Indices>::val... };
template<int N>
struct build_powers {
typedef typename build_powers<N - 1>::type::next type;
};
template<>
struct build_powers<1> {
typedef powers<0> type;
};
and then:
int
main()
{
// we want [0..30] inclusive so pass 31 as exclusive upper limit
typedef build_powers<31>::type power_type;
// 0..30 is 31 powers in all
typedef const int array_type[31];
array_type& ref = power_type::value;
// ref[0] .. ref[30] are the values of Pow<0>::val .. Pow<30>::val
}
So that's with using an array but without dynamic initialization. Since you want the result as a variable and not for TMP I feel this is adequate.
When you do Pow<30>::val; you will instantiate the top of your two templates, then when it get's to zero it will instantiate the specialization, and only the final result will be visible at runtime, since templates are resolved at compile time

C++ metaprogramming

I have the following problem:
Suppose I have some basic counter class Counter. And suppose we also have some sets of classes, that can be counted. Let's name some of them class CountedA and class CountedB.
Now, every class, which can be counted (such as CountedA and CountedB) has the following statically declared parts: one enum and one int part, that acts like a part of counted data.
For example, it's declaration could look the following way:
enum CountedType { A, B };
template <CountedType Type, int N>
class Counted { };
// Now we can declare 'CountedA' and 'CountedB'
typedef Counted<A, 25> CountedA;
typedef Counted<B, 7> CountedB;
Now, the declaration of the counter:
// C++0x variadic or simply bunch of 'typename XX' definitions for C++03
template <typename T0, typename T1, typename ...>
class Counter
{
// I don't know how to implement this
// for now!
int GetTotalN() { ... }
// Retrieve the corresponding type
// so that GetTypeAt<0> returns
// enum from 'T0'
template <int Pos>
CountedType GetTypeAt() { ... }
};
I want to be able to write something like:
class RealCounter : public Counter<CountedA, CountedB> { };
And use it the following way:
RealCounter counter;
int n = counter.GetTotalN();
CountedType type = counter.GetTypeAt<0>();
Now, I'm pretty sure that this can be done. But what's the best way of implementing it? (don't ask me why would I need such crazy kind of things :)
Does boost::mpl offer something for this case?
Thank you.
Small update:
In this particular example, GetTotalN() should return 25 + 7.
If we add, for example, typedef Counted<C, 2> CountedC, then the result for
RealCounter : public Counter<CountedA, CountedB, CountedC>
should become 25 + 7 + 2.
Here's C++03 code which works (for up to 10 template arguments). The main trick is giving class Counter a multiple inheritance, and passing objects of type Counter to function templates which must select a base class. The actual summation is done recursively.
Counter.hpp
enum CountedType { A, B };
template <CountedType Type, int N>
struct Counted {};
struct DummyCounted {};
template <int Pos, typename T>
struct IndexedType {};
template <unsigned int Terms>
struct PartialSum
{
template <typename CounterT>
static int getSum(const CounterT& ctr)
{ return PartialSum<Terms-1>::getSum(ctr) + ctr.template GetNAt<Terms>(); }
};
template <> struct PartialSum<0U>
{
template <typename CounterT>
static int getSum(const CounterT& ctr)
{ return ctr.template GetNAt<0>(); }
};
template <typename T0, typename T1=DummyCounted,
typename T2=DummyCounted, typename T3=DummyCounted,
typename T4=DummyCounted, typename T5=DummyCounted,
typename T6=DummyCounted, typename T7=DummyCounted,
typename T8=DummyCounted, typename T9=DummyCounted>
class Counter :
public IndexedType<0, T0>, public IndexedType<1, T1>,
public IndexedType<2, T2>, public IndexedType<3, T3>,
public IndexedType<4, T4>, public IndexedType<5, T5>,
public IndexedType<6, T6>, public IndexedType<7, T7>,
public IndexedType<8, T8>, public IndexedType<9, T9>
{
public:
static int GetTotalN() {
return PartialSum<9>().getSum( Counter() );
}
template <int Pos>
static CountedType GetTypeAt() { return _getTypeAt<Pos>( Counter() ); }
template <int Pos>
static int GetNAt() { return _getNAt<Pos>( Counter() ); }
private:
template <int Pos, CountedType Type, int N>
static CountedType _getTypeAt(const IndexedType<Pos, Counted<Type,N> >&)
{ return Type; }
template <int Pos, CountedType Type, int N>
static int _getNAt(const IndexedType<Pos, Counted<Type,N> >&)
{ return N; }
template <int Pos>
static int _getNAt(const IndexedType<Pos, DummyCounted>&)
{ return 0; }
};
Counter.cpp
#include "Counter.hpp"
#include <iostream>
typedef Counted<A, 25> CountedA;
typedef Counted<B, 7> CountedB;
class RealCounter : public Counter<CountedA, CountedB> {};
int main()
{
RealCounter counter;
int n = counter.GetTotalN();
CountedType type = counter.GetTypeAt<0>();
std::cout << "n is " << n
<< "\ntype check is " << (type == A) << std::endl;
return 0;
}
Output:
n is 32
type check is 1
That C++0x variadic template stuff looks interesting, but I haven't taken a good look at it yet. But I do think in C++0x, all this example's functions (except main of course) could be constexpr.
I'm not sure why you need to embed those parameters in the templates arguments and not simply in a constructor since they are all the same types for each "derived" CountedA/B types.
Anyways you can embed the resulting types into a std::tuple as shown in the link below (see Message class for an example). Then create a variadic template function similar to the applyTuple version in the link below that will add all your integer arguments and return the final result once all arguments have been unrolled. As for the returning of the enum value for the item in "Pos" simply call the get( tuple ).getEnum() or .value to get it.
How do I expand a tuple into variadic template function's arguments?