生成包含给定类型的 N 个参数的可变参数列表的最佳方法?
Best way to generate a variadic argument list containing N arguments of a given type?
有一个 class 形式的模板:
template <typename ...T> Bag {};
具有许多有用的功能,但一些实现留给派生的 classes。通常这是通过重复 N 次一种类型来实例化的。而不是像这样定义 classes:
class BoolBag3 : public Bag<bool, bool, bool> {};
class IntBag2 : public Bag<int, int> {};
我有兴趣class喜欢:
template<size_t N, typename T> class UniBag : public Bag< ... > {}
特别是当所有类型都相同时,Bag 中的一些纯虚拟可以以通用方式实现。最简单/最优雅的方法是什么?
到目前为止我做了什么:使用 this 答案中的模式生成 TypeSequence
:
template<class T> using InvokeType = typename T::type; // InvokeType is an alias for T::type.
template<class S1, class S2> struct concat;
// Type sequence.
template<typename ... T> struct TypeSequence{ using type = TypeSequence; };
template<typename ... T, typename ... U>
struct concat<TypeSequence<T ...>, TypeSequence<U ...>> : TypeSequence<T ..., U ...>{};
template<class S1, class S2> using Concat = InvokeType<concat<S1, S2>>;
template<typename T, size_t N> struct gen_type_seq;
template<typename T, size_t N> using GenTypeSeq = InvokeType<gen_type_seq<T, N>>;
template<typename T, size_t N>
struct gen_type_seq : Concat<GenTypeSeq<T, N/2>, GenTypeSeq<T, N - N/2>>{};
template<typename T> struct gen_type_seq<T, 0> : TypeSequence<>{};
template<typename T> struct gen_type_seq<T, 1> : TypeSequence<T>{};
然后使用中间体class将TypeSequence
转换为可变参数列表:
template <typename T> class UniBagHelper {};
template <typename ... T> class UniBagHelper<TypeSequence<T ...>> : public Bag<T ...> {};
template <typename T, size_t N> class UniBag : public UniBagHelper<GenTypeSeq<T, N>> {};
UniBag<bool, 4> logicBag;
大概是这样的:
template <typename T, size_t dummy>
using EatIndex = T;
template <typename T, std::size_t... I>
Bag<EatIndex<T, I>...> MakeBagN(std::index_sequence<I...>);
template<size_t N, typename T>
using BagN = decltype(MakeBagN<T>(std::make_index_sequence<N>()));
template<size_t N, typename T>
class UniBag : public BagN<N, T> {};
C++14引入了std::index_sequence
,所以你可能直接有:
template <typename T, std::size_t> using always_t = T;
template <typename T> struct BagTNHelper;
template <typename T, std::size_t ... Is>
struct BagTNHelper<T, std::index_sequence<Is ...>>
{
using type = Bag<always_t<T, Is>...>;
};
template <typename T, size_t N>
using BagTN = typename BagTNHelper<T, std::make_index_sequence<N>>::type;
然后
using BoolBag3 = BagTN<bool, 3>; // Bag<bool, bool, bool>
using IntBag2 = BagTn<int, 2>; // Bag<int, int>
有一个 class 形式的模板:
template <typename ...T> Bag {};
具有许多有用的功能,但一些实现留给派生的 classes。通常这是通过重复 N 次一种类型来实例化的。而不是像这样定义 classes:
class BoolBag3 : public Bag<bool, bool, bool> {};
class IntBag2 : public Bag<int, int> {};
我有兴趣class喜欢:
template<size_t N, typename T> class UniBag : public Bag< ... > {}
特别是当所有类型都相同时,Bag 中的一些纯虚拟可以以通用方式实现。最简单/最优雅的方法是什么?
到目前为止我做了什么:使用 this 答案中的模式生成 TypeSequence
:
template<class T> using InvokeType = typename T::type; // InvokeType is an alias for T::type.
template<class S1, class S2> struct concat;
// Type sequence.
template<typename ... T> struct TypeSequence{ using type = TypeSequence; };
template<typename ... T, typename ... U>
struct concat<TypeSequence<T ...>, TypeSequence<U ...>> : TypeSequence<T ..., U ...>{};
template<class S1, class S2> using Concat = InvokeType<concat<S1, S2>>;
template<typename T, size_t N> struct gen_type_seq;
template<typename T, size_t N> using GenTypeSeq = InvokeType<gen_type_seq<T, N>>;
template<typename T, size_t N>
struct gen_type_seq : Concat<GenTypeSeq<T, N/2>, GenTypeSeq<T, N - N/2>>{};
template<typename T> struct gen_type_seq<T, 0> : TypeSequence<>{};
template<typename T> struct gen_type_seq<T, 1> : TypeSequence<T>{};
然后使用中间体class将TypeSequence
转换为可变参数列表:
template <typename T> class UniBagHelper {};
template <typename ... T> class UniBagHelper<TypeSequence<T ...>> : public Bag<T ...> {};
template <typename T, size_t N> class UniBag : public UniBagHelper<GenTypeSeq<T, N>> {};
UniBag<bool, 4> logicBag;
大概是这样的:
template <typename T, size_t dummy>
using EatIndex = T;
template <typename T, std::size_t... I>
Bag<EatIndex<T, I>...> MakeBagN(std::index_sequence<I...>);
template<size_t N, typename T>
using BagN = decltype(MakeBagN<T>(std::make_index_sequence<N>()));
template<size_t N, typename T>
class UniBag : public BagN<N, T> {};
C++14引入了std::index_sequence
,所以你可能直接有:
template <typename T, std::size_t> using always_t = T;
template <typename T> struct BagTNHelper;
template <typename T, std::size_t ... Is>
struct BagTNHelper<T, std::index_sequence<Is ...>>
{
using type = Bag<always_t<T, Is>...>;
};
template <typename T, size_t N>
using BagTN = typename BagTNHelper<T, std::make_index_sequence<N>>::type;
然后
using BoolBag3 = BagTN<bool, 3>; // Bag<bool, bool, bool>
using IntBag2 = BagTn<int, 2>; // Bag<int, int>