How to instantiate array of objects from template with running parameter - c++

I would appreciate your help for the following simplified example:
template<int N>
struct Q {
struct X {
virtual int v() = 0;
};
template<int i>
struct Z : X {
virtual int v() { return i; }
};
Z<0> z1;
/* ... */
Z<N-1> zN;
X * x[N] = { &z1, /* ... */ &zN };
};
Q<4> q;
The ultimate goal of this example is to create N elements in q.x each pointing to an object instance created from the template with its own parameter .

#include <utility>
#include <tuple>
#include <iostream>
template <int N, typename T = std::make_index_sequence<N>>
struct Q;
template <int N, std::size_t... Is>
struct Q<N, std::index_sequence<Is...>>
{
struct X
{
virtual int v() = 0;
};
template <int i>
struct Z : X
{
virtual int v() { return i; }
};
std::tuple<Z<Is>...> z;
X * x[N] = { &std::get<Is>(z)... };
};
int main()
{
Q<4> q;
std::cout << q.x[0]->v() << std::endl;
std::cout << q.x[1]->v() << std::endl;
}
DEMO

You may use the following:
namespace detail
{
template <template <int> class Z, typename Seq> struct tuple_Z;
template <template <int> class Z, std::size_t ... Is>
struct tuple_Z<Z, std::index_sequence<Is...>>
{
using type = std::tuple<Z<Is>...>;
};
template <typename X, std::size_t N, typename Tuple, std::size_t ... Is>
constexpr std::array<X*, N> make_X_Array(Tuple& t, std::index_sequence<Is...>)
{
return {{(&std::get<Is>(t))...}};
}
}
template<int N>
struct Q {
struct X {
virtual int v() = 0;
};
template<int i>
struct Z : X {
virtual int v() { return i; }
};
Q() : Xs(detail::make_X_Array<X, N>(Zs, std::make_index_sequence<N>())) {}
typename detail::tuple_Z<Z, typename std::make_index_sequence<N>>::type Zs;
std::array<X*, N> Xs =
detail::make_X_Array<X, N>(Zs, std::make_index_sequence<N>());
};
Live example

Related

Passing temporary struct as template argument

I'm in the process of creating a vector class and am trying to figure out ways to reuse the maximum amount of code for different size vectors.
Here's a basic example:
template<typename T, unsigned int D>
class Vector
{
public:
union {
T v[D];
struct {
/* T x;
* T y;
* T z;
* T w;
*/
};
};
Vector()
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = T(0);
}
Vector(T scalar)
{
for(unsigned int i=0; i<D; ++i)
(*this)[i] = scalar;
}
inline T operator[](int i) { return (*this).v[i]; }
};
I want the member variables to be publicly accessible. Ex:
Vector<float,2> vec;
printf("X: %.2f, Y: %.2f\n", vec.x, vec.y);
What I'd like to do is something along the lines of this:
template<typename T>
class Vector2 : public Vector<T,2, struct { T x; T y; }> {};
template<typename T>
class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {};
and have it override a struct in the union:
template<typename T, unsigned int D, struct C>
class Vector
{
public:
union {
T v[D];
// Place the passed struct here
};
};
Is there any feasible way to do this? I do not want to use anything other than the standard library if possible. Thanks in advance.
EDIT: After reading upon all of the answers, I have understood that the way I am using unions is incorrect! Thank you to #M.M for pointing this out. I have since chosen to go a different route, but I have selected the answer that best fit what I was looking for at the time. Once again, thank you for all of the welcomed responses below!
What you are trying to do is not allowed.
Anyway, you can do this:
template<typename T>
struct S { T x; T y; };
template<typename T>
class Vector2 : public Vector<T,2,S<T>> {};
Or this:
template<typename T>
class Vector2 : public Vector<T,2,S> {};
In the second case, Vector can be defined as:
template<typename T, unsigned int D, template<typename> class S>
class Vector {
using MyStruct = S<T>;
// ...
union {
T v[D];
MyStruct myStruct;
};
};
It doesn't scale very well to a large D, but if you're just after the four to six variants I'm imagining, you could partial-specialize a base class:
#include <iostream>
template<typename T, size_t D>
struct VectorBase;
template<typename T>
struct VectorBase<T, 2>
{
constexpr VectorBase() : v{} {}
union {
T v[2];
struct { T x, y; };
};
};
template<typename T>
struct VectorBase<T, 3>
{
constexpr VectorBase() : v{} {}
union {
T v[3];
struct { T x, y, z; };
};
};
template<typename T>
struct VectorBase<T, 4>
{
constexpr VectorBase() : v{} {}
union {
T v[4];
struct { T x, y, z, w; };
};
};
template<typename T, size_t D>
struct Vector : public VectorBase<T, D>
{
using VectorBase<T, D>::v;
using size_type = decltype(D);
using value_type = T;
constexpr Vector() : VectorBase<T,D>{} {}
constexpr Vector(T scalar) {
std::fill(std::begin(v), std::end(v), scalar);
}
constexpr T& operator[](size_type i) const noexcept { return v[i]; }
constexpr const T& operator[](size_type i) noexcept { return v[i]; }
constexpr size_type size() const noexcept { return D; }
constexpr T* data() noexcept { return &v[0]; }
constexpr const T* data() const noexcept { return &v[0]; }
};
template<typename T>
using Vector2 = Vector<T, 2>;
template<typename T>
using Vector3 = Vector<T, 3>;
template<typename T>
using Vector4 = Vector<T, 4>;
int main() {
Vector3<int> v{1};
std::cout << v[0] << ", " << v.z << "\n";
return 0;
}
Live demo: http://ideone.com/T3QHoq
If I understood you correctly your main purpose was to to declare order of fields that corresponds to the array elements of templated class. You cannot do this directly as templates does not accept inline type as parameter. To workaround the problem you could play with non-type template parameters to bind some labels to given index of an array:
#include <cstdio>
#include <unordered_map>
#include <utility>
struct Label { } x, y, z, w;
template <Label&... labels>
struct Pack { };
template <class, class>
struct VectorParent;
template <Label&... labels, size_t... Is>
struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> {
static std::unordered_map<Label *, size_t> label_map;
};
template <Label&... labels, size_t... Is>
std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...};
struct LabelNotFound { };
template <class T, size_t N, Label&... labels>
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> {
static_assert(N == sizeof...(labels),
"the cound of labels should corespond to the number of elements of the vector");
using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map;
T t[N];
T &operator->*(Label& l) {
auto it = label_map.find(&l);
if (it == label_map.end())
throw LabelNotFound{};
return t[it->second];
}
};
int main() {
Vector<float,2,x,y> vec;
vec->*x = 10.0f;
printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00
//vec->*w = 10.1f; //would throw an exception LabelNotFound
}

Creating an instance of a specialized class depending on run-time arguments

Here's the code which demonstrates the idea:
struct A
{
};
struct B
{
};
template<typename T1, typename T2>
struct Specific
{
T1 t1;
T2 t2;
void DoSomething() {}
};
template<typename T1, typename T2>
Specific<T1, T2> create_specific()
{
return Specific<T1, T2>();
}
void my_func(int type1, int type2)
{
if (type1 == 1 && type2 == 1)
{
auto specific = create_specific<A, A>();
specific.DoSomething();
}
else if (type1 == 1 && type2 == 2)
{
auto specific = create_specific<A, B>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 1)
{
auto specific = create_specific<B, A>();
specific.DoSomething();
}
else if (type1 == 2 && type2 == 2)
{
auto specific = create_specific<B, B>();
specific.DoSomething();
}
}
So my_func arguments control which type it will use to DoSomething.
The problem with this approach is that the number of if conditions will grow exponentially. I'm looking for a way to have the compiler do this for me. It would be nice if I could split the logic for every type slot:
if (type1 == 1)
{
create_specific1<A>(...);
}
....
if (type2 == 2)
{
create_specific2<B>(...);
}
Is it at all possible?
UPDATE
Is there any way to implement the template magic in C++11, in particular in Visual C++ 2013?
One way is to use a lookup table like this.
void (*arr[2][2])() =
{
[] { create_specific<A, A>().DoSomething(); },
[] { create_specific<A, B>().DoSomething(); },
[] { create_specific<B, A>().DoSomething(); },
[] { create_specific<B, B>().DoSomething(); }
};
arr[type1-1][type2-1]();
You can also let the compiler produce it for you. This works with two types:
template <std::size_t...> struct index_list {using type = index_list;};
template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};
// inefficient linear recursive method:
template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};
template <typename A, typename B = A,
typename = typename make_index_list<std::tuple_size<A>::value
* std::tuple_size<B>::value - 1>::type>
class create_lookup;
template <typename ... First, typename... Second, std::size_t... indices>
class create_lookup<std::tuple<First...>, std::tuple<Second...>, index_list<indices...>>
{
template <typename T, typename U>
static void work()
{
create_specific<T, U>().DoSomething();
}
public:
static constexpr void (*arr[sizeof...(First)][sizeof...(Second)])() =
{
work< typename std::tuple_element<indices / sizeof...(First), std::tuple<First...>>::type,
typename std::tuple_element<indices % sizeof...(Second), std::tuple<Second...>>::type >...
};
};
template <typename ... F, typename... S, std::size_t... I>
constexpr void (*create_lookup<std::tuple<F...>, std::tuple<S...>, index_list<I...>>::arr[sizeof...(F)][sizeof...(S)])();
int main()
{
auto arr = create_lookup<std::tuple<A, B>>::arr;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
{
std::cout << i << ' ' << j << ": ";
arr[i][j]();
}
}
Since C++14 you could also use a lambda as the expansion pattern, instead of a function template (work). And std::make_index_sequence, and std::tuple_element_t ... ;)
Setting the DoSomething-function to
void DoSomething()
{
std::cout << typeid(T1).name() << ' ' << typeid(T2).name() << '\n';
}
yields the following output:
0 0: A A
0 1: A B
1 0: B A
1 1: B B
Generazalization to more types
This code works with an arbitrary amount of concatenations, specified by the template parameter depth. Example is included, using GCC's demangle function.
#include <iostream>
#include <iomanip>
#include <typeinfo>
#include <tuple>
#include <cxxabi.h>
template<typename... T>
struct Specific
{
void DoSomething()
{
int status;
std::initializer_list<bool> { std::cout << abi::__cxa_demangle(typeid(T).name(), 0, 0, &status) << ' '... };
//std::initializer_list<bool> { std::cout << typeid(T).name() << ' '... };
std::cout << '\n';
}
};
template<typename... T>
Specific<T...> create_specific()
{ return {}; }
template <std::size_t...> struct index_list {using type = index_list;};
template <typename, typename> struct concat;
template <std::size_t... i, std::size_t... j> struct concat<index_list<i...>, index_list<j...>> : index_list<i..., j...> {};
template <std::size_t N>
struct make_index_list : concat<typename make_index_list<N-1>::type, index_list<N>> {};
template <>
struct make_index_list<0> : index_list<0> {};
constexpr std::uintmax_t ipow( std::uintmax_t base, unsigned exp )
{
return exp == 0? 1 : base*ipow(base, exp-1);
}
template <typename T, std::size_t len, std::size_t dim>
struct construct_array
{
using type = typename construct_array<T, len, dim-1>::type[len];
};
template <typename T, std::size_t len>
struct construct_array<T, len, 1>
{
using type = T[len];
};
template <std::size_t depth,
typename A,
typename = typename make_index_list<ipow(std::tuple_size<A>::value, depth)- 1>::type>
class create_lookup;
template <std::size_t depth, typename ... First, std::size_t... indices>
class create_lookup<depth, std::tuple<First...>, index_list<indices...>>
{
template <typename... Args>
static void work()
{
create_specific<Args...>().DoSomething();
}
static constexpr auto length = sizeof...(First);
template <std::size_t index, typename = typename make_index_list<depth-1>::type>
struct get_ptr;
template <std::size_t index, std::size_t ... type_indices>
struct get_ptr<index, index_list<type_indices...>>
{
static constexpr auto value =
work< typename std::tuple_element<index / ipow(length, depth-type_indices-1) % length, std::tuple<First...>>::type... >;
};
public:
static constexpr typename construct_array<void(*)(), length, depth>::type arr
{
get_ptr<indices>::value...
};
};
template <std::size_t depth, typename ... F, std::size_t... I>
constexpr typename construct_array<void(*)(), create_lookup<depth, std::tuple<F...>, index_list<I...>>::length, depth>::type
create_lookup<depth, std::tuple<F...>, index_list<I...>>::arr;
struct A {};
struct B {};
struct C {};
int main()
{
auto arr = create_lookup<3, std::tuple<A, B, C>>::arr;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 3; ++k)
{
std::cout << i << ' ' << j << ' ' << k << ": ";
arr[i][j][k]();
}
}
The same code but without constexpr can be found here.

How to work around partial specialization of function template?

For example, I have a class:
class A
{
enum {N = 5};
double mVariable;
template<class T, int i>
void f(T& t)
{
g(mVariable); // call some function using mVariable.
f<T, i+1>(t); // go to next loop
}
template<class T>
void f<T, N>(T& t)
{} // stop loop when hit N.
};
Partial specialization is not allowed in function template. How do I work around it in my case?
I slightly changed the example of Arne Mertz, like:
template<int n>
struct A
{
enum {N = n};
...
};
and use A like:
A<5> a;
The I cannot compile on Visual Studio 2012. Is it a compiler bug or something else? It is quite strange.
EDIT: Checked. It is a Visual Studio bug. :(
I think Nim gives the most simple way to implement it.
The most straight forward solution is to use a template class instead of a function:
class A
{
enum {N = 5};
double mVariable;
template <class T, int i>
struct fImpl {
static_assert(i<N, "i must be equal to or less than N!");
static void call(T& t, A& a) {
g(a.mVariable);
fImpl<T, i+1>::call(t, a);
}
};
template<class T>
struct fImpl<T,N> {
static void call(T&, A&) {} // stop loop when hit N.
};
public:
template<class T, int i>
void f(T& t)
{
fImpl<T, i>::call(t,*this);
}
};
Example link
You can define a helper class:
template <int i, int M>
struct inc_up_to
{
static const int value = i + 1;
};
template <int i>
struct inc_up_to<i, i>
{
static const int value = i;
};
template<class T, int i>
void f(T& t)
{
if (i < N) {
g(mVariable); // call some function using mVariable.
f<T, inc_up_to<i, N>::value>(t);
}
}
It stops the compile-time recursion by making f<T, N> refer to f<T, N>, but that call is avoided by the run-time condition, breaking the loop.
A simplified and more robust version of the helper (thanks #ArneMertz) is also possible:
template <int i, int M>
struct inc_up_to
{
static const int value = (i >= M ? M : i + 1); // this caps at M
// or this:
static const int value = (i >= M ? i : i + 1); // this leaves i >= M unaffected
};
This doesn't even need the partial specialisation.
With c++11 support, you can do the following:
#include <iostream>
#include <type_traits>
using namespace std;
struct A
{
enum {N = 5};
double mVariable;
void g(int i, double v)
{ std::cout << i << " " << v << std::endl; }
template<int i, class T>
typename enable_if<i >= N>::type f(T& t)
{} // stop loop when hit N.
template<int i, class T>
typename enable_if<i < N>::type f(T& t)
{
g(i, mVariable); // call some function using mVariable.
f<i+1, T>(t); // go to next loop
}
};
int main(void)
{
A a;
int v = 0;
a.f<0>(v);
}
Main reason I like is that you don't need any of the cruft as required by the previous answers...
You can emulate partial specialization of function template with function overloading:
#include <type_traits>
class A
{
enum {N = 5};
double mVariable;
// ...
void g(double)
{
// ...
}
public:
template<class T, int i = 0>
void f(T& t, std::integral_constant<int, i> = std::integral_constant<int, i>())
{
g(mVariable);
f(t, std::integral_constant<int, i + 1>());
}
template<class T>
void f(T& t, std::integral_constant<int, N>)
{
}
};
Example of using:
A a;
int t = 0;
a.f(t);
a.f(t, std::integral_constant<int, 2>()); // if you want to start loop from 2, not from 0
It is a C++11 solution, however (not so much because of std::integral_constant class, but because of default template parameter of function template). It can be made shorter using some additional C++11 features:
template<int i>
using integer = std::integral_constant<int, i>;
template<class T, int i = 0>
void f(T& t, integer<i> = {})
{
g(mVariable);
f(t, integer<i + 1>());
}
template<class T>
void f(T& t, integer<N>)
{
}

Variadic template heterogeneous container

I need to implement some variadic template container class with heterogeneous elements, which allows to iterate by these elements. My first idea is make class with std::tuple member with variadic arguments, but getting elements from tuple by array-like manner (via loops) is impossible:
struct A {void prnt(){std::cout<<"A\n";} };
struct B {void prnt(){std::cout<<"B\n";} };
struct C {void prnt(){std::cout<<"C\n";} };
template<typename...Arg>
struct Prc
{
Prc() : NumElems(sizeof...(Arg)), mems(std::make_tuple(Arg()...)){}
int NumElems;
std::tuple<Arg...> mems;
void process()
{
for(int i=0; i<NumElems; ++i)
std::get<i>(mems).prnt();//It's forbidden: "i" must be a constant
}
};
int main()
{
Prc<A,B,C> obj;
obj.process();
}
Any ideas?
P.S. I don't want use boost heterogenous containers, like boost::variant or boost::any
Here's it done using indicies:
namespace detail
{
template <int... Is>
struct index { };
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> { };
}
template <typename...Args>
struct Prc
{
std::tuple<Args...> mems;
template <int... Is>
void process(detail::index<Is...>)
{
auto l = { (std::get<Is>(mems).prnt(), 0) ... };
}
void process()
{
process(detail::gen_seq<sizeof...(Args)>());
}
};
Here is some code that iterates a tuple:
struct A { void print () { clog << "A" << endl; } };
struct B { void print () { clog << "B" << endl; } };
struct C { void print () { clog << "C" << endl; } };
template<unsigned N>
struct iter
{
template<typename T>
static void f (T &t)
{
iter<N-1>::f (t);
get<N> (t).print ();
}
};
template<>
struct iter<0>
{
template<typename T>
static void f (T &t)
{
get<0> (t).print ();
}
};
And the calling code:
tuple <A,B,C> t;
iter<tuple_size<decltype(t)>::value-1>::f (t);
I think you could modify this to fit your needs. NumElements in your code is known at compile time, so I think you would remove that member altogether.

C++11: Workaround Use Of This Incomplete Type Error?

#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> struct F { constexpr A f() { return A{{ f(i)... }}; } };
template<class X, class Y> struct C;
template<int... i, int... j>
struct C<F<i...>, F<j...>> : F<i..., (sizeof...(i)+j)...> {};
template<int n> struct S : C<S<n/2>, S<n-n/2>> {}; // <--- HERE
template<> struct S<1> : F<0> {};
constexpr auto X = S<N>::f();
int main()
{
cout << X[3] << endl;
}
I'm getting:
test.cpp:15:24: error: invalid use of incomplete type ‘struct C<S<5>, S<5> >’
I suspect this is because the definition of S is using itself as a base class. (Correct?)
What is the best way to fix this?
Update:
Here is the fixed version:
#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> struct F { static constexpr A f() { return A{{ ::f(i)... }}; } };
template<class A, class B> struct C {};
template<int... i, int... j> struct C<F<i...>, F<j...>> : F<i..., (sizeof...(i)+j)...>
{
using T = F<i..., (sizeof...(i)+j)...>;
};
template<int n> struct S : C<typename S<n/2>::T, typename S<n-n/2>::T> {};
template<> struct S<1> : F<0> { using T = F<0>; };
constexpr auto X = S<N>::f();
int main()
{
cout << X[3] << endl;
}
Define C instead of just declaring it.
template<class X, class Y> struct C {};
In the place you use it the partial specialization does not match and
the primary template is instantiated, which is just a declaration.
You may wonder why that specialization is not considered: specializations don't consider conversions, but just the static type. That's why they are so treacherously incompatible with inheritance.
Could you just delegate S::f instead of using inheritance?
template<int n> struct S {
constexpr A f() { return C<S<n/2>, S<n-n/2>>::f(); }
};