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*;
};
Related
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>.
I have the following structs:
template<typename T1, typename T2>
struct A {};
template<typename T>
struct B {};
template<typename A, typename B>
struct C {};
and want to use them as follows:
C<B<int>, A<double, B<int>>> c;
Is there any way to deduce the second template parameter for A, such that I can use it like this?
C<B<int>, A<double>> c;
This should work for any template arguments of C and not just for a particular one (therefore default arguments don't seem to work).
Furthermore a solution for variadic templates would be even better, so instead of
C<B<int>, A<double, B<int>>, A<float, A<double, B<int>>>> c;
something like this would be nice:
C<B<int>, A<double>, A<float>> c;
With a bit of template metaprogramming fun, I was able to solve your problem both for the two-parameter and the variadic case (although in a somewhat narrow way):
// TypeList stuff
template<class... Args>
struct List {
template<class Arg>
using Add = List<Args..., Arg>;
};
template<class List> struct TailI;
template<class A, class... Ar> struct TailI<List<A, Ar...>> {
using type = typename TailI<List<Ar...>>::type;
};
template<class A> struct TailI<List<A>> {
using type = A;
};
template<class List>
using Tail = typename TailI<List>::type;
template<template<class...> class OP, class List> struct rename_impl;
template<template<class...> class OP, class... ListArgs>
struct rename_impl<OP, List<ListArgs...>> {
using type = OP<ListArgs...>;
};
template<template<class...> class OP, class List>
using rename = typename rename_impl<OP, List>::type;
// Actual code solving problem at hand
template<class T1, class T2> struct A{};
template<class... Args> struct C{};
template<class Built, class Next, class... Rest>
struct builder {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = typename builder<NewBuilt, Rest...>::type;
};
template<class Built, class Next>
struct builder<Built, Next> {
using NewBuilt = typename Built::template Add<A<Next, Tail<Built>>>;
using type = rename<C, NewBuilt>;
};
template<class First, class... Rest>
using c_builder = typename builder<List<First>, Rest...>::type;
using t = c_builder<int, double, float>;
// Test driver
#include <utility>
static_assert(std::is_same_v<t, C<int, A<double, int>, A<float, A<double, int>>>>, "");
For the simpler case of
template<typename A, typename B> struct C {};
you can use a helper class to provide you the type you need.
template<typename T1, typename T2>
struct C_Helper
{
using type = C<B<T1>, A<T2, B<T1>>>;
};
and use
using C_Type = typename C_Helper<int, double>::type;
C_Type c;
I haven't thought through how that can be extended to support a variadic class template C,
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;
}
I want to implement a class template that:
behaves like a function
it's input and output variables are all shared.
relatively easy to use.
As a result, I construct the following:
// all input/output variable's base class
class basic_logic_parameter;
// input/output variable, has theire value and iterators to functions that reference to this variable
template <typename FuncIterator, typename ValueType>
class logic_parameter
:public basic_logic_parameter
{
private:
std::list<FuncIterator> _refedFuncs;
ValueType _val;
public:
};
// all `function`'s base class
class basic_logic_function
{
public:
virtual ~basic_logic_function() = 0;
};
// the function, has input/output variable
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base
:public basic_logic_function
{
private:
std::shared_ptr<logic_parameter<FuncIterator, R>> _ret;
std::tuple<std::shared_ptr<logic_parameter<FuncIterator, Args>>...> _args;
public:
template <std::size_t N>
decltype(auto) arg()
{
return std::get<N>(_args);
}
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N> type;
};
template <std::size_t N>
using arg_type_t = arg_type<N>::type;
decltype(auto) ret()
{
return _ret;
}
};
I wish to use as these like:
// drawing need color and a pen
struct Color
{
};
struct Pen
{
};
struct Iter
{
};
class Drawer
:public logic_function_base<Iter, void(Color, Pen)>
{
public:
void draw()
{
arg_type_t<0> pColor; // wrong
}
}
My compiler can not pass this code through, why? I just want convert a template parameter pack to std::tuple of std::shared_ptr of them.
for example:
Given struct A, int, struct C, I want to have:
std::tuple<
std::shared_ptr<logic_parameter<A>>,
std::shared_ptr<logic_parameter<int>>,
std::shared_ptr<logic_parameter<C>>,
>
The problem (once the small errors are fixed1) is that you instantiate:
logic_function_base<Iter, void(Color, Pen)>
...meaning that FuncIterator is Iter and R is void(Color, Pen), so Args is emtpy <>, so decltype(_args) is an empty std::tuple<>, and your code fails to obtain the type of the 0th element of an empty tuple, which is legit.
What you want is partial specialization of logic_function_base:
template <typename F, typename T>
class logic_function_base;
template <typename FuncIterator, typename R, typename... Args>
class logic_function_base<FuncIterator, R(Args...)>: public basic_logic_function {
};
1 Small mistakes in your current code:
template <std::size_t N>
struct arg_type
{
typedef std::tuple_element_t<N, decltype(_args)> type; // Missing the tuple type
};
template <std::size_t N>
using arg_type_t = typename arg_type<N>::type; // Missing a typename
This may not answer your whole question, but you could use the following trait to wrap tuple element types.
template <typename T> struct wrap;
template <typename... T>
struct wrap<std::tuple<T...>> {
using type = std::tuple<std::shared_ptr<logic_parameter<T>>...>;
}
template <typename T>
using wrap_t = typename wrap<T>::type;
You can then use it like this:
std::tuple<int,double,char> t1;
wrap_t<decltype(t)> t2;
The type of t2 is std::tuple<std::shared_ptr<logic_parameter<int>>,std::shared_ptr<logic_parameter<double>>,std::shared_ptr<logic_parameter<char>>>.