I want to declare template:
template <size_t N, class Type> my_tuple
{
using type = ... //something here
};
So that this my_typle<3, std::string>::type,for example, will be the same as this std::tuple<std::string, std::string, std::string>
Please, show, how it can be done in one line, maybe, using std::index_sequence or something from boost or whatever? Or maybe it can not be done just simple?
UPD
Please, note I do not need an std::array, I need to parametrize some variable template with predefined list of types. I have used std::tuple as an example here.
This is fun. Here's a "pure" meta-programming approach to expand the sequence:
template<typename T, typename Seq>
struct expander;
template<typename T, std::size_t... Is>
struct expander<T, std::index_sequence<Is...>> {
template<typename E, std::size_t>
using elem = E;
using type = std::tuple<elem<T, Is>...>;
};
template <size_t N, class Type>
struct my_tuple
{
using type = typename expander<Type, std::make_index_sequence<N>>::type;
};
I say "pure" ironically. It's more akin to the classic meta-programming tricks, nothing else.
Use decltype with return type of function returning tuple<string,string,...repeated N times>:
template<typename T, size_t ... Indices>
auto GetType(std::index_sequence<Indices...>) {
return std::make_tuple( (Indices,T{})... );
}
template <size_t N, class Type> class my_tuple
{
using type = decltype(GetType<Type>(std::make_index_sequence<N>())); //something here
};
template<class T>
struct Dummy;
int main(){
Dummy<my_tuple<3,std::string>::type> d;
error on d gives you tuple<string,string,string>, so it is your desired type.
You can
template <typename...>
struct cat_tuple_type;
template <typename... T1, typename... T2>
struct cat_tuple_type<std::tuple<T1...>, std::tuple<T2...>>
{
using type = std::tuple<T1..., T2...>;
};
template <size_t N, class Type> struct my_tuple
{
static_assert(N>0);
using type = typename cat_tuple_type<std::tuple<Type>, typename my_tuple<N-1, Type>::type>::type;
};
template <class Type> struct my_tuple <1, Type>
{
using type = std::tuple<Type>;
};
Then my_typle<3, std::string>::type gives the type std::tuple<std::string, std::string, std::string>.
Related
I want to have something like:
template <typename... Ts>
using make_variant_t = /* ??? */;
such that, for instance, make_variant_t<Foo, Bar> evaluates as the type
std::variant<Foo, std::vector<Foo>, Bar, std::vector<Bar>>
in that order. How, if it is possible, can this be achieved?
With Boost.Mp11 this is a short, one-liner (as always):
template <typename... Ts>
using make_variant_t = mp_append<variant<Ts, vector<Ts>>...>;
make_variant_t<int, char> will first produce two variants, variant<int, vector<int>> and variant<char, vector<char>>. Those each are "lists" in the Mp11 sense, and mp_append takes a bunch of lists and concatenates them together, producing variant<int, vector<int>, char, vector<char>> as desired. Demo.
Here you go:
namespace impl
{
template <typename R, typename ...P>
struct make_variant {};
template <typename ...R, typename P0, typename ...P>
struct make_variant<std::variant<R...>, P0, P...>
{
using type = typename make_variant<std::variant<R..., P0, std::vector<P0>>, P...>::type;
};
template <typename ...R>
struct make_variant<std::variant<R...>>
{
using type = std::variant<R...>;
};
}
template <typename ...P>
using make_variant_t = typename impl::make_variant<std::variant<>, P...>::type;
Now, make_variant_t<Foo, Bar> should expand to std::variant<Foo, std::vector<Foo>, Bar, std::vector<Bar>>.
Alternative solution with std::tuple under the hood:
namespace impl {
template<class> struct tuple_to_variant;
template<class... Ts>
struct tuple_to_variant<std::tuple<Ts...>> {
using type = std::variant<Ts...>;
};
}
template<class... Ts>
using make_variant_t = typename impl::tuple_to_variant<decltype(
std::tuple_cat(std::declval<std::tuple<Ts, std::vector<Ts>>>()...))>::type;
I have a function:
template <class T, class Array>
void DumpArrayDebug(Array& out, const T& source)
It is supposed to be used to dump data from array classes in Maya (Autodesk app) into regular vector.
Example of such array types:
MFloatArray;
MColorArray;
MIntArray;
These classes have the same interface, yet they have no base class.
Currently I use this function in a following way:
MFloatArray someInternalMayaFloatData;
...
std::vector<float> buffer;
DumpArrayDebug(buffer, someInternalMayaFloatData);
Looking at this code makes me wonder is it possible to somehow tie 2 classes inside the template through something like lookup table?
So that result should look something like this:
template <class T>
void dumpArrayDbg(const T& source, ClassLookupTable<T>& out)
Thus far I was able to come up with the following monstrosity:
template <typename T>
struct ClassLookupTable
{
T classname;
};
template <>
struct ClassLookupTable<MIntArray>
{
std::vector<int> classname;
};
template <>
struct ClassLookupTable<MFloatArray>
{
std::vector<float> classname;
};
template <>
struct ClassLookupTable<MColorArray>
{
std::vector<MColor> classname;
};
template <class T>
void dumpArrayDbg(const T& source, decltype(ClassLookupTable<T>::classname)& out)
{
int length = source.length();
out.clear();
out.resize(length);
source.get(out.data());
}
Is there a more elegant solution?
This is a standard template metaprogramming technique: a traits type. The only things I would change are using standard template metaprogramming idioms (type is the standard name for a type trait, not classname) and avoid having the trait specify vector:
template <typename T>
struct MayaArrayBaseElementTrait; //The primary template should never be used.
template <>
struct MayaArrayBaseElementTrait<MIntArray>
{
using type = int;
};
template <>
struct MayaArrayBaseElementTrait<MFloatArray>
{
using type = float;
};
template <>
struct MayaArrayBaseElementTrait<MColorArray>
{
using type = MColor;
};
template<typename T>
using MayaArrayBaseElementTrait_t = typename MayaArrayBaseElementTrait<T>::type;
template <class T>
void dumpArrayDbg(const T& source, std::vector<MayaArrayBaseElementTrait_t<T>>& out)
{
int length = source.length();
out.clear();
out.resize(length);
source.get(out.data());
}
This way, the mapping is from the Maya array type to the base element type. This gives you the freedom to create mappings to other types besides vector. You could create a std::array or std::list or whatever you like. Also, if you ever want to change the allocator type for the vector, you are free to do so, unlike your original code.
Is there a more elegant solution?
I propose the following...
Given a simple template type list container
template <typename ...>
struct typeList
{ };
and a recursive template as follows
template <typename, typename>
struct lookForType
{ };
template <typename T, typename V, typename ... Ts>
struct lookForType<T, typeList<T, V, Ts...>>
{ using type = V; };
template <typename T, typename U, typename V, typename ... Ts>
struct lookForType<T, typeList<U, V, Ts...>>
: lookForType<T, typeList<Ts...>>
{ };
with an helper using to simplify the extraction of type
template <typename T, typename L>
using lookForType_t = typename lookForType<T, L>::type;
you can create the mapping as follows
using myList = typeList<MIntArray, std::vector<int>,
MFloatArray, std::vector<float>,
MColorArray, std::vector<Color>>;
and get the required type using lookForType or lookForType_t
using l1 = lookForType_t<MIntArray, myList>;
The following is a full compiling example
#include <vector>
#include <type_traits>
template <typename ...>
struct typeList
{ };
template <typename, typename>
struct lookForType
{ };
template <typename T, typename V, typename ... Ts>
struct lookForType<T, typeList<T, V, Ts...>>
{ using type = V; };
template <typename T, typename U, typename V, typename ... Ts>
struct lookForType<T, typeList<U, V, Ts...>>
: lookForType<T, typeList<Ts...>>
{ };
template <typename T, typename L>
using lookForType_t = typename lookForType<T, L>::type;
struct Color {};
struct MFloatArray {};
struct MColorArray {};
struct MIntArray {};
int main()
{
using myList = typeList<MIntArray, std::vector<int>,
MFloatArray, std::vector<float>,
MColorArray, std::vector<Color>>;
using l1 = lookForType_t<MIntArray, myList>;
using l2 = lookForType_t<MFloatArray, myList>;
using l3 = lookForType_t<MColorArray, myList>;
static_assert( std::is_same_v<std::vector<int>, l1>, "!" );
static_assert( std::is_same_v<std::vector<float>, l2>, "!" );
static_assert( std::is_same_v<std::vector<Color>, l3>, "!" );
}
I am trying to recover the non-typename template argument from a variadic pack of template classes (where each class has one non-type argument) so that I can use them as an integer sequence in another type.
The code below shows what I have. The integer sequence / member sequence is cribbed from tuple.
template<std::size_t... Integers>
struct size_t_sequence {
using type = size_t_sequence<Integers...>;
};
template <std::size_t, typename>
struct push_size_t_sequence;
template <std::size_t I, std::size_t... Integers>
struct push_size_t_sequence<I, size_t_sequence<Integers...>>
: size_t_sequence<I, Integers...> {};
template <std::size_t N, std::size_t Head, std::size_t... Tail>
struct make_size_t_sequence
: push_size_t_sequence<Head, typename make_size_t_sequence<N - 1, Tail...>::type>::type {};
template<std::size_t I, std::size_t... OneLeft>
struct make_size_t_sequence <2, I, OneLeft...> :
push_size_t_sequence<I, size_t_sequence<OneLeft...>>::type {};
template<typename... Members>
struct member_sequence {
using type = member_sequence<Members...>;
};
template <typename, typename>
struct push_member_sequence;
template <typename M, typename... Members>
struct push_member_sequence<M, member_sequence<Members...>>
: member_sequence<M, Members...> {};
template <std::size_t N, typename Head, typename... Tail>
struct make_member_sequence
: push_member_sequence<Head, typename make_member_sequence<N - 1, Tail...>::type>::type {};
template<typename M, typename... OneLeft>
struct make_member_sequence <2, M, OneLeft...> :
push_member_sequence<M, member_sequence<OneLeft...>>::type {};
template<typename>
struct unpack_sequence_impl;
template<template<std::size_t> class... T, std::size_t... DimensionSizes>
struct unpack_sequence_impl<member_sequence<T<DimensionSizes>...>> {
using member_types = member_sequence<T<DimensionSizes>...>;
using size_types = size_t_sequence<DimensionSizes...>;
};
template<typename... Members>
struct unpack_sequence :
unpack_sequence_impl<make_member_sequence<sizeof...(Members), Members...>> {
using base_t = unpack_sequence_impl<make_member_sequence<sizeof...(Members), Members...>>;
using member_types = typename base_t::member_types;
using size_types = typename base_t::size_types;
};
template<std::size_t N>
class example {
int s = N;
};
int main()
{
auto mem_sequence = make_member_sequence<3, example<3>, example<2>, example<1>>::type();
auto integer_sequence = make_size_t_sequence<3, 3,2,1>::type();
auto un_mem_sequence = unpack_sequence<example<3>, example<2>, example<1>>::member_types();
auto un_size_sequence = unpack_sequence<example<3>, example<2>, example<1>>::size_types();
}
The types of mem_sequence and integer_sequence are member_sequence<example<3>,example<2>,example<1>> and size_t_sequence<3,2,1>. The types of un_mem_sequence and un_size_sequence should be the same.
How can I accomplish this?
Thank you for your help!
Tim
Edit:
For clarification what I am trying to accomplish is recovering the template arguments from one template class to use them in another. Below are three template classes: MyObject, MyTuple, MyPack. MyTuple takes MyObject objects as its template parameters. I want to recover the MyObject template parameters to use as the template argument for a MyPack object.
template<int N>
MyObject;
template<int... Ns>
MyPack;
template<typename... MyObjects>
MyTuple {};
int main() {
MyTuple<MyObject<1>,MyObject<2>,MyObject<3>> a;
MyPack<1,2,3> b;
}
So I want to pull the arguments from the MyObject's in MyTuple to be used to create a MyPack.
Edit 2:
Second clarification: MyTuple does not just take MyObject types but any type that has one template parameter of int.
template<int N>
MyObject;
template<int N>
MyObject2;
template<int... Ns>
MyPack;
template<typename... MyObjects>
MyTuple {};
int main() {
MyTuple<MyObject<1>,MyObject<2>,MyObject2<1>,MyObject2<2>> a;
MyPack<1,2,1,2> b;
}
template <typename>
struct MakeMyPack;
template <int... Ns>
struct MakeMyPack<MyTuple<MyObject<Ns>...>>
{
using type = MyPack<Ns...>;
};
DEMO
For clarification what I am trying to accomplish is recovering the template arguments from one template class to use them in another. Below are three template classes: MyObject, MyTuple, MyPack. MyTuple takes MyObject objects as its template parameters. I want to recover the MyObject template parameters to use as the template argument for a MyPack object.
Just for fun, I propose a solution more generic, with a double variadic template (template-template and value template), not bounded to MyTuple and MyObject
template <typename>
struct getMyPack;
template <template <typename...> class C,
template <int> class ... Cs, int ... Is>
struct getMyPack<C<Cs<Is>...>>
{ using type = MyPack<Is...>; };
The following is a full compiling example
#include <type_traits>
template <int>
struct MyObject1
{ };
template <int>
struct MyObject2
{ };
template <int...>
struct MyPack
{ };
template <typename...>
struct MyTuple
{ };
template <typename>
struct getMyPack;
template <template <typename...> class C,
template <int> class ... Cs, int ... Is>
struct getMyPack<C<Cs<Is>...>>
{ using type = MyPack<Is...>; };
int main ()
{
using T0 = MyTuple<MyObject1<1>, MyObject2<2>, MyObject1<3>>;
using T1 = MyPack<1, 2, 3>;
using T2 = typename getMyPack<T0>::type;
static_assert( std::is_same<T1, T2>::value, "!" );
}
-- EDIT --
Second clarification: MyTuple does not just take MyObject types but any type that has one template parameter of int.
As I was suspecting.
My solution is unboud to MyObject so should works.
Preceding example modified to show it.
I fully expect this to not be a feature, but figured I may as well ask; is it possible to expand code at compile time using template parameters?
For example:
template <size I>
void foo()
{
...double... vec;
}
Where the ... Is replaced by std::vector< >, I times.
So foo<2>() would compile to:
void foo()
{
std::vector<std::vector<double>> vec;
}
I can't even imagine what the syntax for this would be, so I'm not hopeful.
It would be useful for something like an N dimensional binning class, which could also be implemented through recursion, but not so neatly imo.
Yes, you can. You can do it with class templates and specializations, like this:
template<std::size_t N>
struct MultiDim {
using underlying = typename MultiDim<N-1>::type;
using type = std::vector<underlying>;
};
template<>
struct MultiDim<1> {
using type = std::vector<double>;
};
template<std::size_t N>
using multi_dimensional = typename MultiDim<N>::type;
Hence, multi_dimensional<1> is vector<double>, and multi_dimensional<N> where N>1 is vector<multi_dimensional<N-1>>.
is it possible to expand code at compile time using template parameters?
Directly... I don't think so.
But I suppose you can implement a specific type traits as follows
template <typename T, std::size_t I>
struct bar
{ using type = std::vector<typename bar<T, I-1U>::type>; };
template <typename T>
struct bar<T, 0U>
{ using type = T; };
and use in foo() in this way
template <std::size_t I>
void foo ()
{
typename bar<double, I>::type vec;
}
If you want to be a little more generic, you can also pass std::vector as a template-template parameter; if you define bar as follows
template <template <typename...> class C, typename T, std::size_t I>
struct bar
{ using type = C<typename bar<C, T, I-1U>::type>; };
template <template <typename ...> class C, typename T>
struct bar<C, T, 0U>
{ using type = T; };
foo() become
template <std::size_t I>
void foo ()
{
typename bar<std::vector, double, I>::type vec;
}
template<typename T, typename U>
struct A;
template<std::size_t I>
struct A<int, char[I]> {
using pointer = T*; // does not compile
};
int main() {
A<int, char[3]> a;
}
Is there any way to access the type T (= int) from inside the class template specialization A<int, char[I]>, without explicitly writing the type that is has in the specialization?
Something like this:
template<class T, class U, class=T, class=U>
struct A;
template<std::size_t I, class T, class U>
struct A<int, char[I], T, U> {
using pointer = T*;
};
works. If someone actually passes a type for the second T and U problems develop, but...
Another approach is:
template<class T, class U>
struct A;
// get args from an instance!
template<class A>
struct A_Args;
template<class T_, class U_>
struct A_Args<A<T_,U_>> {
using T = T_; using U = U_;
};
template<class A>
using A_T = typename A_Args<A>::T;
template<class A>
using A_U = typename A_Args<A>::U;
// reflect on our troubles:
template<std::size_t I>
struct A<int, char[I]> {
using pointer = A_T<A>*;
};
where we have a using alias that extracts args from a generic A which we use within the specialization.
This version can be made generic with an interface like:
template<std::size_t I, class Instance>
struct nth_template_arg;
template<std::size_t I, class Instance>
using nth_template_arg_t=typename nth_template_arg<I, Instance>::type;
with the note it will only work with templates that only take type arguments. (implementation left as an exercise. I'd probably use tuple_element for a first pass; using tuples has the downside that they are heavy types, and metaprogramming with heavy types sucks performance and sometimes causes other problems.)
Simply,
#include <type_traits>
template<class T, class U>
struct foo;
template<class T, std::size_t Index>
struct foo<T, char[Index]>
{
using type = T;
};
int
main()
{
static_assert(std::is_same<foo<int, char[3]>::type, int>::value, "");
}
You can try this:
template<typename T, typename U, std::size_t I>
struct A{
using pointer = T*;
};