Variadic template heterogeneous container - c++

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.

Related

C++ Template instancing with mutual reference

Is there a way to allow two or more templates instanciations to mutually refer to each other ?
Example :
/* invalid C++ */
/* we suppose MyTemplate1 and MyTemplate2 are declared */
typedef MyTemplate1<MyInstance2> MyInstance1;
typedef MyTemplate2<MyInstance1> MyInstance2;
I suppose there is none, still asking just in case I missed something.
Adding more precision, I want to achieve such a construction :
/* invalid C++ */
#include <iostream>
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::print(i - 1);
}
}
};
/* of course this is invalid, since you can't reference MyInstance2
before it is declared */
typedef MyStruct1<MyInstance2> MyInstance1;
typedef MyStruct2<MyInstance1> MyInstance2;
int main() {
MyInstance1::print(5);
return 0;
}
output should be :
MyStruct1 : 5
MyStruct2 : 4
MyStruct1 : 3
MyStruct2 : 2
MyStruct1 : 1
MyStruct2 : 0
Please note I'm not trying to achieve a similar output, but a similar construct, where two (or more) templates instances refer to each other
with as few as possible additional code : it shall be easy to do mutual reference instantiation. However, for the implementation code of the two templates, I don't care if they are complicated.
Here's a solution that at least gives the correct output. If it's also a viable solution for your use case is not very clear though but maybe it can at least help you clarify your question a bit more.
#include <iostream>
template <template <typename> typename TemplateT> struct TemplateType {
template <typename typeT>
static void print(unsigned i) {
TemplateT<typeT>::print(i);
}
};
template <typename typeT> struct MyStruct1 {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct1>>(i - 1);
}
}
};
template <typename typeT> struct MyStruct2 {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
typeT::template print<TemplateType<MyStruct2>>(i - 1);
}
}
};
typedef MyStruct1<TemplateType<MyStruct2>> MyInstance1;
int main() {
MyInstance1::print(5);
return 0;
}
One way is to use class forward declaration:
template<typename T> class M
{
static int foo(int i) { return i ? T::foo(i - 1) : 0; }
};
struct A;
struct B;
struct A : M<B>{};
struct B : M<A>{};
Not same code exactly but you have recursion.
I finally found a satisfying construct, which involves using a tierce struct acting as a context to declare subs elements. It isn't forcibly the best solution for anyone, and I will probably have to adapt it a bit more to fit my very need, but here is the code :
#include <iostream>
#include <type_traits>
template <typename K, typename T> struct TypePair {
typedef K key;
typedef T type;
};
template <typename Context, typename P0, typename... PN> struct TypeMap {
template <typename K> struct get {
typedef typename std::conditional<
std::is_same<typename P0::key, K>::value,
typename P0::type::template actual<Context>,
typename TypeMap<Context, PN...>::template get<K>::type>::type type;
};
};
struct TypeNotFound {};
template <typename Context, typename P> struct TypeMap<Context, P> {
template <typename K> struct get {
typedef
typename std::conditional<std::is_same<typename P::key, K>::value,
typename P::type::template actual<Context>,
TypeNotFound>::type type;
};
};
/* defining a context to link all classes together */
template <typename... TN> struct Context {
template <typename K> struct Access {
typedef typename TypeMap<Context<TN...>, TN...>::template get<K>::type type;
};
};
/* templates we want to cross ref, note that context is passed as a parameter*/
template <typename ContextT, typename Id2> struct MyStruct1Actual {
static void print(unsigned i) {
std::cout << "MyStruct1 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id2>::type::print(i - 1);
}
}
};
template <typename ContextT, typename Id1> struct MyStruct2Actual {
static void print(unsigned i) {
std::cout << "MyStruct2 : " << i << std::endl;
if (i > 0) {
ContextT::template Access<Id1>::type::print(i - 1);
}
}
};
/* wrappers to not have to always pass context when instancing templates */
template <typename type> struct MyStruct1 {
template <typename ContextT> using actual = MyStruct1Actual<ContextT, type>;
};
template <typename type> struct MyStruct2 {
template <typename ContextT> using actual = MyStruct2Actual<ContextT, type>;
};
/* Enum and dummy id, could simply use Enum actually, but using classes a Id
can prove to be more elegant with complex structures, expecially as it could be
used to automatically create pairs instead of having to precise Id */
enum Ids : int { Struct1, Struct2 };
template <Ids id> struct Id {};
// instancing all stuff withing context
// clang-format off
typedef Context<
TypePair< Id<Struct1>, MyStruct1< Id<Struct2> > >,
TypePair< Id<Struct2>, MyStruct2< Id<Struct1> > >
> Ctx;
// clang-format on
typedef Ctx::Access<Id<Struct1>>::type S1;
int main() {
S1::print(5);
return 0;
}
Shortening names an giving more meaning than Context or TypePair will be mandatory, but the idea is here.

Calling template function from inner class

I have a class like this to call a function depending on the type. I try to compile it, but have error error C2059 syntax error : 'template'
class A
{
call_1()
{
B<type> b;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
return word;
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
/**/
}
};
}
What am I doing wrong?
First, let's rewrite your example into something that is readable and is closer to being compilable, and we also print "1" or "2" in say() to know which function gets called:
#include <iostream>
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
};
OK, so first, you are trying to specialize B inside of A. This is not allowed, so let't move it outside of A:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
Next up, you are using the same template parameter (T) in both B and say(). You don't need to repeat T, so let's delete it:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
Finally, call_1() cannot be defined before the specialization of A::B, so we need to move it outside too:
using type = int;
class A {
void call_1();
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
void A::call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
This should now compile and do what you want. Calling call_1() will print 1. If you change the type from int to void:
using type = void;
it will print 2.

How to initialise an array of N function pointers to function templates indexed from 0..N-1?

Given a function pointer array of function_sig, I want to initialise it to a set of template function pointers that are index via a template parameter. Is this possible?
E.g.
template<int I>
void fn() { /* do something */ }
typedef void(*function_sig)();
template<int ARRAY_SIZE>
struct items
{
static function_sig array[ARRAY_SIZE];
};
template<int ARRAY_SIZE>
function_sig items<ARRAY_SIZE>::array = { /* what do I put here? */ };
So, is there something that I can put in the initialiser list, such that items<ARRAY_SIZE>::array will be initialised to { fn<0>, fn<1>, ..., fn<ARRAY_SIZE-1> }?
NOTE: I know of a way to do this with preprocessor magic, but I'd like to try without that. Currently, I'm thinking I'll have to do away with the array and replace it with something that would act like an array, but that would lead to a search of O(N) when indexing the pseudo-array, which I'd like to not do.
The problem is to get a variadic range from 0 to ARRAY_SIZE - 1.
I propose a solution that transfer array in a base class itemsH
#include <iostream>
template <std::size_t ...>
struct range
{ };
template <std::size_t N, std::size_t ... Next>
struct rangeH
{ using type = typename rangeH<N-1U, N-1U, Next ... >::type; };
template <std::size_t ... Next >
struct rangeH<0U, Next ... >
{ using type = range<Next ... >; };
template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }
typedef void(*function_sig)();
template <typename T>
struct itemsH;
template <std::size_t ... RNG>
struct itemsH<range<RNG...>>
{
static function_sig array[sizeof...(RNG)];
};
template<std::size_t ARRAY_SIZE>
struct items : public itemsH<typename rangeH<ARRAY_SIZE>::type>
{ };
template <std::size_t ... RNG>
function_sig itemsH<range<RNG...>>::array[sizeof...(RNG)] = { fn<RNG>... };
int main ()
{
items<10> i_10;
for ( unsigned ui = 0U ; ui < 10 ; ++ui )
i_10.array[ui]();
return 0;
}
p.s.: I've changed the type of ARRAY_SIZE from int to size_t; hoping isn't a problem
p.s.2: sorry for my bad English.
--- edit: added C++14 example ---
If you (when you) can use C++14, the you can use std::index_sequence and std::make_index_sequence, throwing away range and rangeH.
The example become
#include <utility>
#include <iostream>
template<int I>
void fn() { std::cout << "[" << I << "]" << std::endl; }
typedef void(*function_sig)();
template <typename T>
struct itemsH;
template <std::size_t ... RNG>
struct itemsH<std::index_sequence<RNG...>>
{ static function_sig array[sizeof...(RNG)]; };
template<std::size_t ARRAY_SIZE>
struct items : public itemsH<std::make_index_sequence<ARRAY_SIZE>>
{ };
template <std::size_t ... RNG>
function_sig itemsH<std::index_sequence<RNG...>>::array[sizeof...(RNG)]
= { fn<RNG>... };
int main ()
{
items<10> i_10;
for ( unsigned ui = 0U ; ui < 10 ; ++ui )
i_10.array[ui]();
return 0;
}
#include <array>
template<int... Is>
struct int_seq { };
namespace detail {
template<int I, int... Is>
struct make_int_seq : make_int_seq<I - 1, I, Is...> { };
template<int... Is>
struct make_int_seq<0, Is...> {
using type = int_seq<0, Is...>;
};
} // namespace detail
template<int SizeN>
using make_int_seq = typename detail::make_int_seq<SizeN - 1>::type;
template<int I>
void fn() { /* do something */ }
//typedef void(*function_sig)();
using function_sig = void(*)();
template<int ARRAY_SIZE>
struct items {
static std::array<function_sig, ARRAY_SIZE> array;
};
template<int... Is>
std::array<function_sig, sizeof...(Is)> create_items_array(int_seq<Is...>) {
return {{ &fn<Is>... }};
}
template<int ARRAY_SIZE>
std::array<function_sig, ARRAY_SIZE> items<ARRAY_SIZE>::array
= create_items_array(make_int_seq<ARRAY_SIZE>{});
Online Demo
With C++14, int_seq et al disappear in favor of std::integer_sequence et al.

How can I initialize an array in compile-time with some elements given manually?

I'm using an array of pointer to function. I wrote the code like this since some of elements can not be expressed with function template.
extern void zero(); // isr 0 is defined somewhere else
void one() {
// isr 1
}
template <std::size_t N>
void Nth() {
// isr N
}
using func = void (*)();
constexpr func interrupt_vector[256] = {
&zero,
&one,
&Nth<2>,
&Nth<3>,
...
&Nth<254>,
&Nth<255>,
};
I've read about static table generation with variadic template, but those were about initializing the whole array.
How can I simplify the code?
# Actually It's a part of interrupt vector. Since it should be called directly, I cannot use template specialization such as
template <>
void Nth<0>() {
zero();
}
## Edited the code. I think that cout things were confusing.
If you can change to use std::array then something like this would work.
using func = void (*)();
template<int...>
struct index_sequence { };
template<int From, int N, int... Is>
struct make_index_sequence_from : make_index_sequence_from<From, N - 1, N - 1, Is...> { };
template<int From, int... Is>
struct make_index_sequence_from<From, From, Is...> : index_sequence<Is...> { };
template<int... Is> constexpr
std::array<func, 256> make_interrupt_vector_array(index_sequence<Is...>)
{
return {{zero, one, Nth<Is>...}};
}
constexpr
std::array<func, 256> make_interrupt_vector_array()
{
return make_interrupt_vector_array(make_index_sequence_from<2, 256>());
}
constexpr auto interrupt_vector = make_interrupt_vector_array();
I would recommended that you wrap your function around a class/struct so that you can take advantage of template specialization and declare your function as static inside of the class/struct
#include <iostream>
template <std::size_t N>
struct Nth
{
static void print()
{
std::cout << N << "!!" << std::endl;
}
};
template <>
struct Nth<0>
{
static void print()
{
std::cout << "Zero!!" << std::endl;
}
};
template <>
struct Nth<1>
{
static void print()
{
std::cout << "One!!" << std::endl;
}
};
int main()
{
Nth<0>::print();
Nth<1>::print();
Nth<2>::print();
}
Following may help:
#if 1 // Not in C++11
#include <cstdint>
template <std::size_t ...> struct index_sequence {};
template <std::size_t N, std::size_t ...Is>
struct make_index_sequence : make_index_sequence <N - 1, N - 1, Is...> {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {};
#endif // make_index_sequence
using func = void (*)();
namespace detail
{
// general case
template <std::size_t N>
struct FuncPtr { static constexpr func value = &Nth<N>; };
// Some specializations // not necessary at the beginning
template <>
struct FuncPtr<0u> { static constexpr func value = &zero; };
template <>
struct FuncPtr<1u> { static constexpr func value = &one; };
// Function to create the array:
template <std::size_t ... Is>
constexpr std::array<func, sizeof...(Is)>
FuncPtrArray(index_sequence<Is...>)
{
return std::array<func, sizeof...(Is)>{{FuncPtr<Is>::value...}};
}
} // namespace detail
constexpr std::array<func, 256> interrupt_vector =
detail::FuncPtrArray(make_index_sequence<256>());

Get type for index in tuple during runtime

I know, there are several topic, asking very close things but I don't get it to work in my case.
I would like to build a templated factory with index access during runtime. Therefore I have several types with the same base type. The factory gets the types which it is able to procude per template parameters. The call to the factory just gives an index. This is a small example:
#include <iostream>
#include <memory>
#include <tuple>
struct Base {
};
struct A : Base {
A(int) { std::cout << "A" << std::endl; }
};
struct B : Base {
B(int) { std::cout << "B" << std::endl; }
};
struct C : Base {
C(int) { std::cout << "C" << std::endl; }
};
template <typename ... Types>
struct Factory {
typedef std::tuple<Types...> TypesTuple;
std::shared_ptr<Base> operator ()(int index) {
return produce(index);
}
std::shared_ptr<Base> produce(int index) {
switch (index) {
case 0: return std::make_shared<typename std::tuple_element<0, TypesTuple>::type>(42);
case 1: return std::make_shared<typename std::tuple_element<1, TypesTuple>::type>(42);
}
throw;
}
};
//==============================================================================
int main() {
Factory<A, C> factory_ac;
auto a1 = factory_ac(0);
auto c1 = factory_ac(1);
Factory<A, B, C> factory_bc;
auto a2 = factory_bc(0);
auto b2 = factory_bc(1);
auto c2 = factory_bc(2);
}
I tried to overload the produce method with
template <typename = typename std::enable_if<std::tuple_size<TypesTuple>::value==2>::type>
counting up the size and providing the respective switch statements, but this does not compile, overload not allowed.
I tried using https://stackoverflow.com/a/7383493/2524462 but I couldn't get it to work, because the parameter packs don't expand with a lambda and wrapping it in a template function I get problems with the constexpr array, since I don't have trivial types.
Boost MPL for_eachcomes to mind, but I got problems compiling, because my types are not trivially constructable.
So how would one change the factory to get the main to compile and work?
It seems this can be done quite straight forward:
template <typename T>
std::shared_ptr<Base> make() {
return std::make_shared<T>();
}
template <typename... T>
class Factory {
public:
std::shared_ptr<Base> operator()(int index) {
static constexpr std::shared_ptr<Base> (*factories[])() = {
&make<T>...
};
if (index < 0 && sizeof...(T) <= index) {
throw std::range_error("type index out of range");
}
return (factories[index])();
}
};
I'm currently not in the position to compile the code but something along this lines should work: the idea is to create an array of factory functions and just call into this array.
If I have understood your requirements correctly, I think this does what you want:
template<int... Is>
struct indices { typedef indices type; };
template<int N, int... Is>
struct make_indices : make_indices<N - 1, N - 1, Is...> { };
template<int... Is>
struct make_indices<0, Is...> : indices<Is...> { };
template<typename... Types>
struct Factory
{
typedef std::tuple<Types...> TypesTuple;
std::shared_ptr<Base> operator()(int const index)
{
return produce(index);
}
std::shared_ptr<Base> produce(int const index)
{
return produce_impl(make_indices<sizeof...(Types)>(), index);
}
template<int I, int... Is>
std::shared_ptr<Base> produce_impl(indices<I, Is...>, int const index)
{
if (I == index) {
return std::make_shared<typename std::tuple_element<I, TypesTuple>::type>(42);
}
return produce_impl(indices<Is...>(), index);
}
std::shared_ptr<Base> produce_impl(indices<>, int const index)
{
throw "Uh-oh!";
}
};
See output here.