ACB*_*ACB 11 c++ templates variadic c++11
我最近了解了模板模板参数的存在,现在想知道这样的事情是否可行:
template<template<class... > class Container, typename... args>
struct ContainerTemplate
{
using container = std::tuple<Container<args...>...>;
};
Run Code Online (Sandbox Code Playgroud)
我想要的是一个模板,它获取一个Container或一些其他模板类作为模板模板参数,然后扩展其余的模板参数,如果Container有N个模板参数,我给args的N*M模板参数我用N模板args获得M模板实例化,例如:
ContainerTemplate<std::vector, int, short, char>
//assuming std::vector takes only 1 arg for simplicity
Run Code Online (Sandbox Code Playgroud)
应该导致
container = std::tuple<std::vector<int>, std::vector<short>, std::vector<char>>
Run Code Online (Sandbox Code Playgroud)
而
ContainerTemplate<std::map, int, int, short, short>
//assuming std::map takes only 2 args for simplicity
Run Code Online (Sandbox Code Playgroud)
应该导致
container = std::tuple<std::map<int, int>, std::map<short, short>>
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?问题是你可以找出容器有多少模板args.
编辑:如果您需要在大小为N的元组中传递其他参数,那就没问题
ContainerTemplate<std::map, std::tuple<int, int>, std::tuple<short, short>>
Run Code Online (Sandbox Code Playgroud)
Edit2:所以我实际上找到了一种确定模板模板参数数量的方法
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;
};
Run Code Online (Sandbox Code Playgroud)
有了这个,下面的代码将打印2
std::cout << SizeofTemplateTemplate<std::vector, int, std::allocator<int>, int, int>::Size << std::endl;
Run Code Online (Sandbox Code Playgroud)
我现在唯一的问题是dyp的解决方案崩溃了visual studio编译器xD
Edit3:原始问题的完整解决方案:https://stackoverflow.com/a/22302867/1366591
根据你的第一次尝试,这是不可能的,但根据你的编辑,可以将参数打包在std::tuples中.在这种情况下,Embed下面的模板会在每个模板中包含参数tuple并将其嵌入Container.
查看实例.
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>...>;
};
Run Code Online (Sandbox Code Playgroud)
一般来说,放置...在内部...是非常棘手的,并且只能在有限的情况下发生(我只以有用的方式管理过一次).
这是一个不需要将模板模板参数预先打包为元组的解决方案.这种打包是自动完成的,你只需要在一个元组(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...>;
};
Run Code Online (Sandbox Code Playgroud)
用法示例:
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{} );
}
Run Code Online (Sandbox Code Playgroud)
所以我实际上设法找到解决问题的方法.我会留下iavr的答案作为soloution,因为语法很好,它也允许使用模板重载.所以只是为了完整起见并证明它确实可行:
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...>
{
typedef char yes[1];
typedef char no[2];
template<typename...>
struct Test;
template<typename... args>
struct Test<TypeList<args...>>
{
template<template<class...> class Testee>
static yes& TestTemplate(Testee<args...>* arg);
template<template<class...> class Testee>
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;
};
template<template<class...> class Template, size_t N, typename... Args>
struct GenerateNTuple;
template<template<class...> class Template, typename... Args>
struct GenerateNTuple<Template, 0, Args...>
{
using type = TypeList<>;
using rest = TypeList<Args...>;
};
template<template<class...> class Template, size_t N, typename Head, typename... Args>
struct GenerateNTuple<Template, N, Head, Args...>
{
using type = typename GenerateNTuple<Template, N - 1, Args...>::type::template PushFront<Head>::type_list;
using rest = typename GenerateNTuple<Template, N - 1, Args...>::rest;
};
template<template<class...> class Container, typename... args>
struct DeduceType;
template<template<class...> class Container, typename... args>
struct DeduceType<Container, TypeList<args...>>
{
using type = Container<args...>;
};
template<template<class...> class Template, typename... Args>
struct ContainerTemplate;
template<template<class...> class Template, typename... Args>
struct ContainerTemplate<Template, TypeList<Args...>>
{
using packed = GenerateNTuple<Template, SizeofTemplateTemplate<Template, Args...>::Size, Args...>;
using type = typename ContainerTemplate<Template, typename packed::rest>::type::template PushFront<typename DeduceType<Template, typename packed::type>::type>::type_list;
};
template<template<class...> class Template>
struct ContainerTemplate<Template, TypeList<>>
{
using type = TypeList<>;
};
template<template<class...> class Template, typename... Args>
using ContainerTypeList = typename ContainerTemplate<Template, TypeList<Args...>>::type;
Run Code Online (Sandbox Code Playgroud)
用法是这样的:
template<typename T>
using vec = std::vector<T>;
std::cout << typeid(ContainerTypeList<vec, int, short>).name() << std::endl;
Run Code Online (Sandbox Code Playgroud)