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 ...;
Related
For educational purposes (while reading book Modern C++ Design - A Alexandrescu) I want to write some helper to delete all types in parameter pack before type T.
For example delete_until_T<C,A,B,C,D> must be opened like tuple<C,D> or just <C,D>.
As I understand it may be done in old enough recursive way and non recursive way with C++17.
In this piece of code i wanna do it in non recursive way using std::conditional.
//https://stackoverflow.com/a/23863962/12575933 - based on this answer
#include <tuple>
#include <type_traits>
template<typename...Ts>
using tuple_cat_t = decltype(std::tuple_cat(std::declval<Ts>()...));
template<class T, class ... Ts>
using delete_untill_T = tuple_cat_t
<
typename std::conditional
<
std::is_same_v<T,Ts>||bool_func<>,
std::tuple<Ts>,
std::tuple<>
>::type...
> ;
The first question is how to make a variable or function or struct which value can be changed during this parameter pack opening and used in std::conditional? I want to make bool_func<> which returns false before std::is_same returns true while opening, and after that returns false.
If it's possible, my second question is how to remove tuple and pass just parameters in parameter pack to template function.
Or may be there is another way to delete types before T? (recursive algorithm will do). Or with C++ 20 features?
One way of implementing this is to use partial specializations to match when the type that you're looking for is found in the variadic parameters.
// recursive case, first 2 template parameters don't match
template<typename T, typename, typename ...Ts>
struct delete_until_impl : delete_until_impl<T, Ts...> {};
// base case, first 2 parameters match
template<typename T, typename ...Ts>
struct delete_until_impl<T, T, Ts...>
{
using type = std::tuple<T, Ts...>;
};
// convenience alias to avoid having to say typename everywhere
template<typename ...Ts>
using delete_until_T = typename delete_until_impl<Ts...>::type;
Here's a demo.
Suppose I've got a tuple type std::tuple<x,y,z>, or maybe std::tuple<a,b>. I'd like a general purpose way to transform the types in my tuple, e.g. "functionize" to get
std::tuple<std::function<void(x)>,
std::function<void(y)>,
std::function<void(z)>>
or maybe get storage for shared_pointers like
std::tuple<std::shared_pointer<a>,
std::shared_pointer<b>>
How would I achieve this with C++17? C++20 answers interesting but not applicable in my current situation.
Motivation:
I've got a class that's going to be parameterized by a list of arbitrary and not necessarily unique types, and would like to have a std::function member for each type in the list.
Template specialization is probably the easiest way.
template <typename T>
struct functionize;
template <typename... Ts>
struct functionize<std::tuple<Ts...>> {
using type = std::tuple<std::function<void(Ts)>...>;
}
using MyTuple = std::tuple<int, double, char>;
using MyTupleFunctionized = typename functionize<MyTuple>::type;
To make it more generic, you can accept a template template parameter to apply to the pack.
template <typename Tuple, template <typename> typename Component>
struct transform_tuple;
template <typename... Ts, template <typename> typename Component>
struct transform_tuple<std::tuple<Ts...>, Component> {
using type = std::tuple<Component<Ts>...>;
}
using MyTuple = std::tuple<int, double, char>;
using MyTransformedTuple = typename transform_tuple<MyTuple, std::shared_ptr>::type;
The more general solution works best with c++17 or later. Prior to that it would only match on a template with exactly 1 parameter. After c++17 it would also be able to match on something like std::vector which has 2 template parameters where the second one has a default argument.
Edit:
As pointed out in the comments by #Jarod42 and #Caleth we can improve on this a bit more.
template <typename Tuple, template <typename...> typename Component>
struct transform_tuple;
A parameter pack for the template template parameter allows us to pass something like a std::vector in from c++11 and forward. That only leaves issues if we want to pass something that mixes type and non-type parameters, like std::array.
We can partially solve that issue by using template aliases.
template <typename T>
using FixedArray10 = std::array<T, 10>;
using MyTransformedTuple = typename transform_tuple<MyTuple, FixedArray10>::type;
I'm fiddling around with template metaprogramming, specifically with type sequences and STL-like algorithms working on those sequences. One thing I ran into was the transformation of predicates, for example by binding one of their parameters
I think it's hard to describe my problem without first providing some background information. Here's an example:
#include <type_traits>
// Type sequence
template<class... T>
struct typeseq
{
static constexpr size_t Size = sizeof...(T);
};
// Some algorithm
template<class TS, template<class...> class P>
using remove_if = /* ... some template logic ... */;
// Usage example:
using a = typeseq<int, float, char*, double*>;
using b = remove_if<a, std::is_pointer>; // b is typeseq<int, float>
As shown here, remove_if requires a predicate that serves as an oracle for the removal algorithm to determine which of the elements to remove. As we're dealing with metaprogramming, it is in the form of a template template parameter. ( Note that P is using a variadic template parameter here. Although I'm expecting a unary template, an earlier version of C++ had the restriction that a variadic template argument can't be used as a non-variadic template parameter, which severely restricts predicate transformations. ) It requires that the predicate, when instantiated, resolves to a type that has a nested compile time value member that is convertible to bool.
All is well, but say you want to remove every type that is convertible to int. Obviously, std::is_convertible is a binary predicate, but remove_if above requires a unary predicate. We just need to fix the second template argument to int. Let's define a bind2nd:
template<template<class, class...> class P, class BIND>
struct bind2nd
{
template<class T1, class... Tn> using type = P<T1, BIND, Tn...>;
};
// and now we should be able to do:
using c = remove_if<ts, bind2nd<std::is_convertible, int>::type>; // c is typeseq<char*, double*>;
Unfortunately, this fails to compile on latest Clang and MSVC++. Apparently, the issue is the pack expansion of Tn... into std::is_convertible<T1, BIND, Tn...> while std::is_convertible only has 2 template parameters. It doesn't seem to matter that the pack is empty in practice (isolated example)
I'd rather not provide 'overloads' for any required arity of the predicate passed into bind2nd. Is there a way to detect the arity of P in bind2nd above? GCC allows me to partially specialize it for non-variadic versions of P:
template<template<class, class> class P, class BIND>
struct bind2nd<P, BIND>
{
template<class T1> using type = P<T1, BIND>;
};
But unfortunately GCC wasn't the one that was complaining in the first place. I also doubt how conformant such a partial specialization is. Is there a way around this? Is it possible to detect the actual arity of a template template parameter, and do something different based on that information?
I think I found a workaround.
The problem seems related to type aliases - they seem to directly pass along any template arguments, rather than instantiating the type as is the case with a class or struct. We can use this in our favor, by using a struct as an intermediate step:
template<template<class, class...> class P, class BIND>
struct bind2nd
{
template<class... Tn>
struct impl
{
using type = P<Tn...>;
};
template<class T1, class... Tn> using type = typename impl<T1, BIND, Tn...>::type;
};
Now it works :). It's a bit convoluted though. I wonder if this is all according to standard, but it seems to compile on all major compilers.
Edit: Why am I complicating things by using nested types and aliases? I can just as well use derivation for predicates:
template<template<class, class...> class P, class BIND>
struct bind2nd
{
template<class T1, class... Tn>
struct type : P<T1, BIND, Tn...> { };
};
Clean and simple. And it makes it almost identical to the first definition of bind2nd in the OP.
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.
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...);
}
};