Simultaneous recursion over multiple parameter packs - c++

Is it possible in C++ to simultaneously recurse over multiple (in my case two) parameter packs? How?
To give a better idea of exactly what I'm asking, I currently have a class template as follows:
template<template<typename> class C, typename... Rest>
class Inherit {};
template<template<typename> class C, typename T, typename... Rest>
class Inherit<C, T, Rest...> :
public C<T>,
public Inherit<C, Rest...>
{
};
I'm using this class template in another class which takes a parameter pack Ts to have that class inherit multiple times from a templated interface. For example:
template<typename T>
class Interface
{
...
};
template<typename... Ts>
class Example :
public Inherit<Interface, Ts...>
{
};
Now, what I would like to do is this:
template<typename T, const char* N>
class Interface
{
...
};
template<typename... Ts, const char*... Ns>
class Example :
public Inherit<Interface, Ts..., Ns...>
{
};
I need a templated Inherit class that can recurse and pick an element off of both the Ts and the Ns parameter pack at once (assuming that parameter pack Ts and Ns have the same length). I'm not versed enough in template programming to know if this is even possible?

I would argue that you don't need this Inherit class template based on the examples you gave. Here's how I'd write your first example:
template<typename T>
class Interface
{
...
};
template<typename... Ts>
class Example : public Interface<Ts>...
{
};
and your second example:
template<typename T, const char* N>
class Interface
{
};
template<typename, const char*...>
class Example;
template<typename... Ts, const char*... Ns>
class Example<std::tuple<Ts...>, Ns...> : public Interface<Ts, Ns>...
{
};

template <typename... Ts, const char*... Ns> class Example; is wrong.
You might want something like (no recursion)
template<typename T, const char* N>
class Interface
{
// ...
};
template<typename T, typename Names> class Example;
template<typename... Ts, const char*... Ns>
class Example<std::tuple<Ts...>, std::integer_sequence<const char*, Ns...>> :
public: Interface<Ts, Ns>...
{
};
Interface<Ts, Ns>... requires that both packs have the same size.

Related

Correct variadic pack expansion

I am working on C++20 implementation of tuple:
template<size_t INDEX, typename T>
struct wrap { [[no_unique_address]] T data {}; };
template<typename...>
class base {};
template<size_t... INDEX, typename... Ts>
class base<index_sequence<INDEX...>, Ts...> : public wrap<INDEX, Ts>... {
public:
constexpr base( const Ts &... args ) : /* !! HERE SHALL THE MAGIC COME */ {}
};
template<typename... Ts>
class tuple : public base<index_sequence_for<Ts...>, Ts...> {
public:
/* Inherit base constructors */
using base<index_sequence_for<Ts...>, Ts...>::base;
};
My question is: How to correctly implement the code in place of /* !! HERE SHALL THE MAGIC COME */ to call base, means wrap<> constructor - the wrap copy constructor taking the corresponding instance of T (expanded from base's template variadic pack Ts) hold in args?
Thanks in advance to anyone willing to help.
Parameter pack expansion also applies to member initializer lists, so you can simply do this:
template<size_t INDEX, typename T>
struct wrap { [[no_unique_address]] T data {}; };
template<typename...>
class base {};
template<size_t... INDEX, typename... Ts>
class base<std::index_sequence<INDEX...>, Ts...> : public wrap<INDEX, Ts>... {
public:
constexpr base(const Ts&... args) : wrap<INDEX, Ts>{args}... {}
};
Demo.

How to specialize a templatized class for taking a method function type that takes no parameters?

template<typename T, typename U>
class Caller{};
template<typename T, typename RET>
class Caller<T, RET()> {}
template<typename T, typename RET, typename HEAD, typename TAIL>
class Caller<T, RET(HEAD,TAIL...)> : Caller<T, RET(TAIL...)> {}
class MyClass { void foo(int,int){}};
Caller<decltype(&MyClass::foo), decltype(&MyClass::foo)> caller();
I want this code to hit the third definition twice, then the second definition once.
I've tried many variations on this and it either seems to jump right to the top-most one or complain about not enough or too many template types.
It wasn't picking up the specialization because it wasn't specialized as an object method. You have to have void(ClassType::*)(int,int) for it to be an object method.
template<typename A>
class Thing<RET(A::*)()> {
public:
Thing(int a){printf("In 2\n");}
};
template<typename A, typename RET, typename HEAD, typename... TAIL>
class Thing<RET(A::*)(HEAD, TAIL...)> : Thing<RET(A::*)(TAIL...)> {
public:
Thing(int a) : Thing<RET(A::*)(TAIL...)>(a){printf("In 3\n");}
};
class MyClass {public: void foo(int a,int b){}};
// this will print 2, 3, 3
Thing<decltype(&MyClass::foo)> thing(1);

C++ Variadic class template design

I'm working on a mix-in type Config Reader class which supports reading configuration data from environment, command line, files, etc..
I was kind of following the std::tuple type design:
template <class... Ts> struct ConfigReader {};
template <class T, class... Ts>
class ConfigReader<T, Ts...> : ConfigReader<Ts...>
{
public:
typedef boost::fusion::set<T, Ts...> sequence_type;
ConfigReader(T t, Ts... ts)
: ConfigReader<Ts...>(ts...)
, parameters_(t, ts...)
{
this->init();
}
private:
sequence_type parameters_;
void init()
{
boost::fusion::for_each(parameters_, SetFromEnvironment());
boost::fusion::for_each(parameters_, SetFromCommandLine());
boost::fusion::for_each(parameters_, SetFromConfigFile());
}
};
But I realized that I could also define this without the recursive inheritance
template <class T, class... Ts>
class ConfigReader<T, Ts...>
{
public:
typedef boost::fusion::set<T, Ts...> sequence_type;
ConfigReader(T t, Ts... ts)
: parameters_(t, ts...)
{
this->init();
}
template <class Type>
typename boost::fusion::result_of::value_at_key<Sequence const, Type>::type get()
{
return boost::fusion::at_key<Type>(parameters);
}
private:
sequence_type parameters_;
void init()
{
boost::fusion::for_each(parameters_, SetFromEnvironment());
boost::fusion::for_each(parameters_, SetFromCommandLine());
boost::fusion::for_each(parameters_, SetFromConfigFile());
}
};
The latter case seems to work better because init() is only called once which is really what I want. But now I'm confused as to what are the differences between the two? Am I losing something without the recursive inheritance?
Simplified usage would be.. (Ignoring Parameter type structs)
int main()
{
ConfigReader<Start, End, Resources> configReader(Start(), End("infinity"), Resources());
Start startTime = configReader.get<Start>();
}
The recursive approach makes no sense. Consider an example case where you want:
ConfigReader<A, B, C> reader(A{}, B{}, C{});
In the recursive case, you end up with this hierarchy:
ConfigReader<A, B, C> has three readers: A, B, C
|
|
V
ConfigReader<B, C> has two readers: B, C
|
|
V
ConfigReader<C> has one reader: C
You have 6 readers, when you meant for only 3! What you probably meant when you did the recursive hierarchy is for each instantiation to just have one reader: not all of them. That is:
template <typename T, typename... Ts>
struct ConfigReader : ConfigReader<Ts...> {
T current;
ConfigReader(T t, Ts... ts)
: ConfigReader<Ts...>(ts...)
, current(t)
{ }
};
But what you're doing with the boost fusion set accomplishes that directly. Though, with C++11, you should probably just stick with:
template <typename... T>
struct ConfigReader {
std::tuple<T...> readers;
};
It should suit your purpose.

Heterogenous storage of variadic class parameter member variables

I have a variadic class template that is used to create a top-level class for a variable number of classes. Each class that is to go in the top-level class is derived from a base class, as there is common functionality for them. I don't know the best way to store the derived classes in the parent class, but still be able to access the full functionality of the derived class.
If I store the variadic args in a vector, they'll all be stored as a base class and I can't access the derived functionality. If I store them in a tuple, I can't work out how to access the functions by derived type. If I try to access them as discussed here on SO then make_unique isn't available (C++14?).
So, I want to do the following:
class BaseElement {
public:
virtual int polymorphicFunction() {return 0;};
};
class DerivedElement1 : public BaseElement {
public:
virtual int polymorphicFunction() {return 1;};
}
class DerivedElement2 : public BaseElement {
public:
virtual int polymorphicFunction() {return 2;};
}
template<typename... systems> // systems will always be of derived class of BaseElement
class System {
System() : subsystems(systems{}...) {} ; // all variadic elements stored in tuple
// tuple used below, the system elements don't need to be stored in a container, I just want to access them
// I'd be happy to use a vector or access them directly as a member variable
// provided that I can access the derived class. I can't use RTTI.
const std::tuple<systems...> subSystems;
// pointer or reference, I don't mind, but pd1/2 will always exist,
// (but perhaps be NULL), even if there is no derived element passed to the template parameter
DerivedElement1 *pd1;
DerivedElement2 *pd2;
};
//Desired usage
System<DerivedElement1> sys; // sys->pd1 == &derivedElement1WithinTuple, sys->pd2 == NULL
System<DerivedElement2> sys; // sys->pd2 == &derivedElement2WithinTuple, sys->pd2 == NULL
System<DerivedElement1, DerivedElement2> sys; // sys->pd1 == &derivedElement1WithinTuple, sys->pd1 == &derivedElement1WithinTuple
Does anyone have any suggestions as to how I might achieve this please?
With:
#include <cstdint>
#include <type_traits>
#include <tuple>
namespace detail
{
template <typename T, typename... Ts> struct get_index;
template <typename T, typename... Ts>
struct get_index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename Tail, typename... Ts>
struct get_index<T, Tail, Ts...> :
std::integral_constant<std::size_t, 1 + get_index<T, Ts...>::value> {};
template <typename T>
struct get_index<T> : std::integral_constant<std::size_t, 0> {}; // Not found
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>& t) noexcept
-> typename std::enable_if<N < sizeof...(Ts), decltype(&std::get<N < sizeof...(Ts) ? N : 0>(t))>::type
{
return &std::get<N>(t);
}
template <std::size_t N, typename... Ts>
constexpr
auto
safe_get(const std::tuple<Ts...>&) noexcept
-> typename std::enable_if<sizeof...(Ts) <= N, nullptr_t>::type
{
return nullptr;
}
}
You may have:
template <typename... systems>
class System {
public:
constexpr System() :
subSystems(),
pd1(detail::safe_get<detail::get_index<DerivedElement1, systems...>::value>(subSystems)),
pd2(detail::safe_get<detail::get_index<DerivedElement2, systems...>::value>(subSystems))
{}
const std::tuple<systems...> subSystems;
const DerivedElement1 *pd1;
const DerivedElement2 *pd2;
};

VS2010 C++ variadic template example

I have a class template and I can't seem to figure out how to perform a Variadic Template style instantiation.
Here is the "code" so far of what I'm looking for:
template<typename _Classname, typename... Args>
class CFunctorStartExT
{
friend class CXXFactory;
protected:
template<typename U>
CFunctorStartExT(typename U& _functor, Args&... args) :
m_Functor(_functor),
m_args(args)
{
}
virtual bool ProcessLoop(CSomeClass* pThread)
{
return m_Functor(pThread, m_args);
}
protected:
_Classname& m_Functor;
Args... m_args;
};
Obviously this won't compile :). The idea is to create a class that can store the values passed in (if any.. it might just have _Classname/U defined) on the constructor so they can be retrieved later to pass to m_Functor in another function.
First: can Variadic Template even be done in VS2010? I am getting compile problems just with the template declaration error C2143: syntax error : missing ',' before '...' from the line template<typename _Classname, typename... Args>
Second, can what I am trying to accomplish be done? Thanks!
Visual C++ 2010 does not support variadic templates.
I believe the following will do what you want. First you need a utility:
// make_tuple_indices
template <size_t...> struct tuple_indices {};
template <size_t _Sp, class _IntTuple, size_t _Ep>
struct make_indices_imp;
template <size_t _Sp, size_t ..._Indices, size_t _Ep>
struct make_indices_imp<_Sp, tuple_indices<_Indices...>, _Ep>
{
typedef typename make_indices_imp<_Sp+1, tuple_indices<_Indices..., _Sp>, _Ep>::type type;
};
template <size_t _Ep, size_t ..._Indices>
struct make_indices_imp<_Ep, tuple_indices<_Indices...>, _Ep>
{
typedef tuple_indices<_Indices...> type;
};
template <size_t _Ep, size_t _Sp = 0>
struct make_tuple_indices
{
static_assert(_Sp <= _Ep, "make_tuple_indices input error");
typedef typename make_indices_imp<_Sp, tuple_indices<>, _Ep>::type type;
};
Then you can use this to help you expand a tuple holding your arguments:
template<typename _Classname, typename... Args>
class CFunctorStartExT
{
friend class CXXFactory;
protected:
template<typename U>
CFunctorStartExT(U& _functor, Args&... args) :
m_Functor(_functor),
m_args(args...)
{
}
virtual bool ProcessLoop(CSomeClass* pThread)
{
return ProcessLoop(pThread,
typename make_tuple_indices<sizeof...(Args)>::type());
}
protected:
_Classname& m_Functor;
std::tuple<Args...> m_args;
private:
template <std::size_t ...Indx>
bool ProcessLoop(CSomeClass* pThread, tuple_indices<Indx...>)
{
return m_Functor(pThread, std::get<Indx>(m_args)...);
}
};
As far as VS2010 variadic template support: I have no idea.
Variadic templates are a patch upon a kludge upon a hack -- you're not going to enjoy this. The way to do this (off the top of my head) is to use template specialization together with inheritance. Something along these lines:
template<typename Classname, typename... Args>
class CFunctorStartExT;
template<typename Classname, typename Arg0, typename... Args>
class CFunctorStartExT : private CFunctorStartExT<Classname, Args...> {
protected:
Arg0 m_arg;
};
template<typename Classname>
class CFunctorStartExT {
protected:
Classname &m_Functor;
};
I've never done this before, and haven't tested it, but this is the general idea. You could have a look at a std::tuple implementation for something that actually works.