I recently learned about the existence of template template parameters and was now wondering if something like this would be possible:
template<template<class... > class Container, typename... args>
struct ContainerTemplate
{
using container = std::tuple<Container<args...>...>;
};
what i want is a template that gets a Container or some other template class as a template template parameter and then expands the rest of the template arguments in such a way that if Container has N template args and i give N * M template arguments for args i get M template instantiations with N template args eg:
ContainerTemplate<std::vector, int, short, char>
//assuming std::vector takes only 1 arg for simplicity
should result in
container = std::tuple<std::vector<int>, std::vector<short>, std::vector<char>>
while
ContainerTemplate<std::map, int, int, short, short>
//assuming std::map takes only 2 args for simplicity
should result in
container = std::tuple<std::map<int, int>, std::map<short, short>>
Is there any way to do this? The question would be wether you could find out how many template args Container takes or not.
Edit: it would be ok if you were required to pass the additional arguments in tuples of size N
ContainerTemplate<std::map, std::tuple<int, int>, std::tuple<short, short>>
Edit2: so i actually found a way to determine the number of template template arguments
template<typename... T>
struct TypeList
{
static const size_t Size = sizeof...(T);
template<typename T2>
struct PushFront
{
typedef TypeList<T2, T...> type_list;
};
};
template<template<class...> class Template, typename... Args>
struct SizeofTemplateTemplate
{
static const size_t Size = 0;
typedef TypeList<> type;
};
template<template<class...> class Template, typename Arg, typename... Args>
struct SizeofTemplateTemplate<Template, Arg, Args...>
{
template<typename... Args>
struct Test;
typedef char yes[1];
typedef char no[2];
template<typename... Args>
struct Test<TypeList<Args...>>
{
template<template<class...> class Template>
static yes& TestTemplate(Template<Args...>* arg);
template<template<class...> class Template>
static no& TestTemplate(...);
};
typedef typename SizeofTemplateTemplate<Template, Args...>::type::PushFront<Arg>::type_list type;
static const size_t Size = sizeof(Test<type>::TestTemplate<Template>(0)) == sizeof(yes) ? type::Size : SizeofTemplateTemplate<Template, Args...>::Size;
};
with this, the following code will print 2
std::cout << SizeofTemplateTemplate<std::vector, int, std::allocator<int>, int, int>::Size << std::endl;
only problem i have now is that dyp's solution crashes the visual studio compiler xD
Edit3: complete solution for the original question here: https://stackoverflow.com/a/22302867/1366591
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
A variadic template is a class or function template that supports an arbitrary number of arguments. This mechanism is especially useful to C++ library developers: You can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.
In UML models, template parameters are formal parameters that once bound to actual values, called template arguments, make templates usable model elements. You can use template parameters to create general definitions of particular types of template.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.
It is not possible according to your first attempt, but it is possible according to your edit, where arguments are packed within std::tuple
's. In this case, template Embed
below takes arguments in each tuple
and embeds them in Container
.
See live example.
template<template<class... > class Container, typename P>
struct Embed_t;
template<template<class... > class Container, typename... T>
struct Embed_t <Container, std::tuple <T...> >
{
using type = Container <T...>;
};
template<template<class... > class Container, typename P>
using Embed = typename Embed_t <Container, P>::type;
template<template<class... > class Container, typename... P>
struct ContainerTemplate
{
using container = std::tuple<Embed <Container, P>...>;
};
In general, placing ...
within ...
is very tricky and can happen only in limited circumstances (I've only managed this once in a useful way).
Here's a solution that doesn't require pre-packing the template template-arguments as tuples. This packing is done automatically, you only have to provide how many arguments are to be packed in one tuple (N
).
#include <tuple>
template<template<class...> class Container, int N>
struct join_n_impl
{
template<class ArgTuple, int I = 0, class Joined = std::tuple<>>
struct helper;
template<class Arg, class... Rest, int I, class... Joined>
struct helper<std::tuple<Arg, Rest...>, I, std::tuple<Joined...>>
: helper<std::tuple<Rest...>, I+1, std::tuple<Joined..., Arg>>
{};
template<class Arg, class... Rest, class... Joined>
struct helper<std::tuple<Arg, Rest...>, N, std::tuple<Joined...>>
{
using type = Container<Joined...>;
using rest = std::tuple<Arg, Rest...>;
};
template<class... Joined>
struct helper<std::tuple<>, N, std::tuple<Joined...>>
{
using type = Container<Joined...>;
using rest = std::tuple<>;
};
};
template<template<class...> class Container, int N, class ArgTuple>
using join_n = typename join_n_impl<Container, N>::template helper<ArgTuple>;
template<template<class...> class Container, int N, class Args,
class Collected = std::tuple<>>
struct pack_n;
template<template<class...> class Container, int N, class... Args,
class... Collected>
struct pack_n<Container, N, std::tuple<Args...>, std::tuple<Collected...>>
{
static_assert(sizeof...(Args) % N == 0,
"Number of arguments is not divisible by N.");
using joiner = join_n<Container, N, std::tuple<Args...>>;
using joined = typename joiner::type;
using rest = typename joiner::rest;
using type = typename pack_n<Container, N, rest,
std::tuple<Collected..., joined>>::type;
};
template<template<class...> class Container, int N, class... Collected>
struct pack_n<Container, N, std::tuple<>, std::tuple<Collected...>>
{
using type = std::tuple<Collected...>;
};
Usage example:
template<class, class>
struct test {};
#include <iostream>
template<class T>
void print_type(T) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
int main()
{
using to_pack = std::tuple<int, double, int, char, int, bool>;
print_type( pack_n<test, 2, to_pack>::type{} );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With