unpacking variadic template arguments to define new template arguments - c++

I am new to template programming and I have two questions...Hopefully someone can help me.
I am trying to use variadic templates to generate a new input to another variadic template.
In other words, I have a class
template <std::size_t N, std::size_t... M>
class Class1 {
}
I want to use the integer values represented by N,M to generate a new set of std::bitset type inputs to another templated class
template <typename T, typename... Ts>
class Class2 {
}
So for example if I use Class1<10,20,25> I want inside the body of Class1 to
create a
Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>>
variable. Is there a simple way to do this using C++11?
My second question then is how can I abstract this even more so that the unpacking is not specific to the std::bitset class?
Is there a way to modify the Class1 template definition so that I can expand some arbitrary templated class that I develop instead of std::bitset?

You might write something like:
template <std::size_t N, std::size_t... M>
class Class1 {
template <template <typename, typename...> class C,
template <std::size_t> class inner>
using rebind_with_type = C<inner<N>, inner<M>...>;
};
And then
Class1<10, 20, 25>::rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<10>, std::bit_set<20>, std::bit_set<25>>
And if call it with dependent name, don't forget typename/template:
typename Class1<N, M...>::template rebind_with_type<Class2, std::bit_set>
// -> Class2<std::bit_set<N>, std::bit_set<M>...>

I find you can think of the ... operator on parameter packs in this way:
f(g(Xs)...);
will expand to
f(g(Xs1), g(Xs2), ..., g(Xsn));
for any operations f and g. Really all it is doing is adding a comma seperated list of g applied to each of the parameters provided. The ... defines where it should begin the expansion
These operations can be for types or values, so in your case our f is Class2<...> and our g is std::bitset our type would look like
Class2<std::bitset<N>, std::bitset<M>...>
The first one needs to be explicitly added since it's not part of the parameter pack ofcourse.

The other answers are excellent but let me give you an even more generic version of the accepted answer. You basically create a using alias that takes two templates, the first is the class that will hold the class templates as template parameters, and the second the template (like bitset) that you want to pass types to.
template<template<class...> class Y, template<class...> class Z, class... Ts>
using fold_types_into_t = Y<Z<Ts>...>;
template<template<class...> class Y, template<auto...> class Z, auto... Vs>
using fold_values_into_t = Y<Z<Vs>...>;
template<class,class...>
struct Class2;
template <std::size_t N, std::size_t... M>
class Class1 {
// Class2<std::bitset<10>, std::bitset<20>, std::bitset<25>>
using T=fold_values_into_t<Class2, std::bitset, N, M...>;
};
There could also be added support for classes that take values as well as types.

Related

C++ variadic template with tuple as template parameter

I would like to have something like this (warning: invalid code):
template<std::tuple<typename T, typename... Args>>
class nDimensionalPoint
This way, I could work with n-dimensional points one dimension at a time.
Of course, I could avoid the std::tuple part by declaring
template<typename T, typename... Args> and simply passing
the coordinates in each dimension in a vector of its own,
but that creates the following difficulty: One needs to somehow bind together
the coordinates hidden in args.... Therefore, I would like a cleaner way
of making it explicit that the underlying type is variadic tuple.
How this could be done?
You might declare it as partial specialization as
template<typename>
class nDimensionalPoint;
template<typename T, typename... Args>
class nDimensionalPoint<std::tuple<T, Args...>> {};
then use it like
nDimensionalPoint<std::tuple<int, char>> dp ...;

Expanding template parameter pack to declare class members

First, I have a template class:
template <typename T>
class Component;
Then I would like to create a class that can hold an arbitrary set of Component<T>'s as members, e.g. for N=2:
template <typename T, typename U>
class Aggregate
{
private:
Component<T>* m_comp1;
Component<U>* m_comp2;
};
At first glance, this looks like using variadic template would be a natural application.
template <typename... Comps>
class Aggregate
{
// what should go here for me to get Component<Comp1>, Component<Comp2>, ...?
};
However, I am unable to write the code that would essentially allow me to go from T, U, ... -> C<T>, C<U>, .... Currently, I have this achieved by creating a partial specialization for each N=1,2,3,4,... case, but this yields a lot of duplicated boilerplate code (and I would like to avoid having to write the Aggregate class to take in the template parameters directly as <Comp<T>,Comp<U>,...>). Is there a way to achieve the above? Thank you for any feedback/help in advance.
try using a tuple:
template <typename... Comps>
using Aggregate = std::tuple<Component<Comps>*...>;
There's no simple solution. Use std::tuple. Otherwise you'd need to reimplement it yourself, which is not trivial.

Simpler syntax to bind some parameters to a template template paramater

A class ExpectTTs takes a number of template template parameters:
template< template<typename> class... TT >
struct ExpectTTs {};
Another type requires two template parameters. I need to fix one and pass the rest to ExpectTTs.
Currently I'm using this solution:
template< typename T >
struct TwoTs {
template< typename U >
struct Inner {};
};
ExpectTTs< TwoTs<int>::Inner >
Is it possible to change something so that I can pass a simple template instantiation like TwoTs<int> to ExpectTTs?
In several points in my codebase I have expressions like ExpectTTs< A, B, C<int>::Inner, D, E<int,int>::Inner, F<void>::Inner > and it seems unnecessary hard to read and write.
Any C++ version is fine.
If you have a template taking two parameters you cannot only specify one and obtain a template template. That is simply not possible. You also cannot create a template template alias as you can create a template alias with using. C++ does not make it easy to work with template templates, you can basically only use them when you fully instantiate them or when you pass them as a parameter to a template.
You also cannot get ExpectTTs really working with both template template parameters and type template parameters, since C++ strictly distinguishes between them (otherwise you could do something like let ExpectTTs extract the inner type). Maybe you could let ExpectTTs only take type template parameters, and make also A, B, and D have an Inner template while themselves being types, so you can let ExpectTTs always do the work for extracting the Inners. But then of course, you wouldn't be able to pass STL-templates like std::optional directly.
One small thing you could (in my opinion) improve in your design is using something like this:
#include <utility> // For the example
#include <optional>
template<template<class> class...>
struct ExpectTTs {};
template<template<class...> class TT, class T>
struct bind {
template<class U>
using bound_t = TT<T, U>;
};
ExpectTTs<std::optional, bind<std::pair, int>::bound_t> e{};
It's maybe even more verbose, but it does not need the intrusive Inner type and returns exactly the template template you want and not some other stand-in.

Variadic template parameter pack to accept only unsigned ints or size_t as its type

I'm trying to use a set of template classes with a variadic parameter. I have several options ahead of me that I could choose from. Before any of my templates are declared or defined I currently have these prototypes: I'm familiar with templates but I haven't had much experience with variadic types when working with templates so the syntax does get a little confusing to me at times. Being that they are all empty shells they do currently compile.
template<typename ClassType, typename... Args> class MatrixReference;
template<typename ClassType, typename... Args> class MatrixStorage;
template<typename ClassType, typename... Args> class MatrixAllocation;
I have a User End Class that will use these classes depending on the intentions of use; it is currently an empty shell for now until I get the other classes defined correctly with the appropriate behavior:
template<typename ClassType, typename... Args>
class Matrix {
};
The rest of the class from the prototypes shown above will inherit from a base class so that the above user class will have a container of them such that the container would be: std::vector<std::unique_ptr<MatrixBase>> or std::vector<shared_ptr<MatrixBase>> and the vector will only ever contain 1 of each type from the listed prototypes. For instance vector[0] would contain a MatrixStorage, vector[1] would container a MatrixReference and vector[2] would contain a MatrixAllocation. Each of these classes have different responsibilities as their names suggest. The storage class will contain a raw stack copy of the elements. The reference class will be use to reference those copies. The allocation class will be used when the elements are declared on the heap. The base class looks like this:
template <typename ClassType = void>
class MatrixBase {
protected:
MatrixBase(){}
virtual ~MatrixBase(){}
}; // Matrix
I have also thought about inheriting them from a non template base as this class does nothing but serve the purpose of being able to store different class types into a single container. I may go ahead and change this to a non template type but for now I'm using it as is to stay with the conventions of its derived types.
Now onto the declaration of my class templates: I really only need to use one of them here since all follow the same pattern, but I'll show all 3 anyway since they are currently empty shells.
// Stores All Of The Contents Of The Matrix
template<typename ClassType, typename... Args>
class MatrixStorage : public MatrixBase<ClassType> {
}; // MatrixStorage
// Used To Reference The Storage Class Of The Matrix
template<typename ClassType, typename... Args>
class MatrixReference : public MatrixBase<ClassType> {
}; // MatrixReference
// Used Only When User Wants To Create A Matrix On The Heap
template<typename ClassType, typename... Args>
class MatrixAllocation : public MatrixBase<ClassType> {
}; // MatrixAllocation
The design approach that I'm looking for is that when this class is used it follows the pattern where the first type is always the type of data the matrix will store either it be an int, float, or some other user defined type; the next parameter is where the use of a variadic parameter comes in so that if one instantiates a template as such:
Matrix<float,2,2> mat2x2; // Default constructor making it empty
This will generate a 2x2 sized Matrix of floats
Matrix<int,3,3,3> mat3x3x3;
This would generate a 3x3x3 volumetric matrix of ints
So the variadic template part will always be + integers and the minimal requirement would be Matrix<type, 1> where this would be in a sense a scalar or a single element matrix or a 1x1 matrix.
This is where I'm presented with a few options. I could use the following
size_t... N
unsigned... D
typename... Args
Currently at the moment as you can see it is declared with the last of the choices. So now comes the main question:
If I decided to use the Parameter Pack where I have a helper class as such:
template <typename ClassType,typename... Dimensions>
class DimensionPack {
public:
typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim;
const unsigned int numarguments = sizeof...(Dimensions);
};
The question becomes; is there a known way to make the Variadic Parameter of the same type namely either size_t or unsigned int? If so an example would be appreciated or a reference link would help as well; I've searched and haven't found anything helpful that is similar enough to help me through this.
If there isn't I don't mind having to use size_t or unsigned int but I was preferring to be able to use the helper template to pack and unpack the variadic parameters for me this way I don't have to implement that in each and every class.
I also have a 2 other derived classes not shown here but one would be used with logging them to the screen, where the other would be used with reading and parsing from a file and writing out to a file.
Also as a side note: For extremely large data sets or extremely large sized Matrices: I also have this helper class to use for them:
template<typename ClassType, std::size_t bufferSize>
class MatrixBuffer {
static std::vector<ClassType> matrixBuffer = std::vector<ClassType>().reserve( bufferSize );
};
Edit
I forgot to add this to the original question but I'm adding it now for a little more clarity. I do have a need to test each variadic parameter's value to see if it is odd or even and the results of them will be stored into a vector with a size of the amount of parameters storing a 0 for even or a 1 for odd. This is one of the reasons why I was leaning towards the use of a parameter pack because I could just pass it to a helper function that would return back the vector that is needed.
std::size_t... Args and typename... Args are not the same. The first would expect integers like
Matrix<float,2,2> mat2x2;
while the second would expect types instead.
Of course, you could use std::integral_constant, but that'd be more verbose:
template <std::size_t N>
using size = std::integral_constant<std::size_t, N>;
Matrix<float,size<2>,size<2>> mat2x2;
On the other hand you could use std::index_sequence:
template<typename ClassType, std::size_t... Dims>
class Matrix {
using Dimensions = std::index_sequence<Dims...>;
};
Using static_assert it is possible to check at compile time :
template <typename ClassType,typename... Dimensions>
class DimensionPack {
public:
DimensionPack(const Dimensions&... args){
checkType<Dimensions...>(args...);
}
~DimensionPack(){}
private:
template<typename T> void checkType(const T& t) {
static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
}
template<typename T, typename... V> void checkType(const T& t, const V&... v) {
static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
checkType<V...>(v...);
}
};

How to test if a type parameter is a template type

Say I have a template class like so:
template < typename TParam >
class Test
{
// content
};
I want to pull out the first template parameter of TParam if it's a specialization of a class template. Something like:
template < typename TParam >
class Test
{
using TParamInner = TemplateType<TParam>::Type;
// use TParamInner here
};
Additional info:
I have access to all of C++98.
I have access to a subset of C++11.
I would prefer to avoid the stdlib if possible (assume this is
because I'm using an embedded system for which no stdlib is available and/or because I am heavily memory-constrained)
You can get close with something like:
template <class >
struct first_template_param;
template <template <class...> class Z, class T, class... Ts>
struct first_template_param<Z<T, Ts...>> {
using type = T;
}
It won't handle std::array or any other class templates that take non-type template parameters. But it'll handle all the "normal" class templates. You can always then add extra specializations for all the ones you want:
template <class T, size_t N>
struct first_template_param<std::array<T,N>> {
using type = T;
}
Thanks to #Barry for spurring the solution along.
It's not a complete answer for all template types, but it works for templates where all parameters are types, which is a large number of the most useful templates.
template < typename Head, typename ... Tail >
struct split { using first = Head; };
template <class >
struct cls_template_info; // fails on non-templates
template <template <class...> class Z, class... Ts>
struct cls_template_info<Z<Ts...>>
{
using type = typename split<Ts...>::first; // typename used to disambiguate
};
This can then be used as using T = cls_template_info<std::vector<int>>::first;.
You can't. A template type is never carried up to runtime. You have to instantiate it (this leads to a complete new type), and the compiler then generates the needed code to make it appear as if you have defined specifically for the type parameters you specified. Indeed, in old compilers (this has been solved a lot of time ago) when you instantiate a generic type in several compilation units, that lead to several repetitions of the same code in the final program. But as I've said, this has been solved time ago.