模板模板模板的语法问题
Trouble with syntax for template-template-templates
我正在写一个元函数MultipartitionWithUnaryPredicates
,用于表单
MultipartitionWithUnaryPredicates<Pack<Args...>, UnaryPredicates...>::type
因此,类型模板包将由一元谓词包 UnaryPredicates...
进行多分区,分区按照列出的一元谓词的顺序进行。如果您不确定我的意思,请查看下面代码中的 main()(它工作正常):
#include <iostream>
#include <type_traits>
#include <typeInfo>
template <template <typename> class, typename, typename, typename> struct Helper;
template <template <typename> class UnaryPredicate, template <typename...> class P, typename... Types1, typename... Types2>
struct Helper<UnaryPredicate, P<>, P<Types1...>, P<Types2...>> {
using type = P<Types1..., Types2...>;
using head = P<Types1...>;
using tail = P<Types2...>;
};
template <template <typename> class UnaryPredicate, template <typename...> class P, typename First, typename... Rest, typename... Types1, typename... Types2>
struct Helper<UnaryPredicate, P<First, Rest...>, P<Types1...>, P<Types2...>> : std::conditional<UnaryPredicate<First>::value,
Helper<UnaryPredicate, P<Rest...>, P<Types1..., First>, P<Types2...>>,
Helper<UnaryPredicate, P<Rest...>, P<Types1...>, P<Types2..., First>>
>::type {};
template <typename, template <typename> class> struct PartitionWithUnaryPredicate;
template <template <typename> class UnaryPredicate, template <typename...> class P, typename... Ts>
struct PartitionWithUnaryPredicate<P<Ts...>, UnaryPredicate> : Helper<UnaryPredicate, P<Ts...>, P<>, P<>> {};
template <typename, template <typename> class...> struct MultipartitionWithUnaryPredicates;
template <typename Pack, template <typename> class UnaryPredicate>
struct MultipartitionWithUnaryPredicates<Pack, UnaryPredicate> : PartitionWithUnaryPredicate<Pack, UnaryPredicate> {};
template <typename, typename> struct Join;
template <template <typename...> class P, typename... Types1, typename... Types2>
struct Join<P<Types1...>, P<Types2...>> {
using type = P<Types1..., Types2...>;
};
//template <template <typename, template <typename> class> class Pack, typename... Ts>
//struct JoinSpecial : Join<typename Pack::head, typename MultipartitionWithUnaryPredicates<typename Pack::tail, Ts...>::type> {};
template <typename Pack, template <typename> class First, template <typename> class... Rest>
struct MultipartitionWithUnaryPredicates<Pack, First, Rest...> : Join<typename PartitionWithUnaryPredicate<Pack, First>::head, typename MultipartitionWithUnaryPredicates<typename PartitionWithUnaryPredicate<Pack, First>::tail, Rest...>::type> {};
// The above can be improved, since PartitionWithUnaryPredicate<Pack, First> is being computed twice.
// -----------------------------------------------------------------------------------------------------------------------------------------------
// Testing:
template <typename...> struct Pack {};
template <typename Last>
struct Pack<Last> {
static void print() {std::cout << typeid(Last).name() << std::endl;}
};
template <typename First, typename ... Rest>
struct Pack<First, Rest...> {
static void print() {std::cout << typeid(First).name() << ' '; Pack<Rest...>::print();}
};
struct Thing {};
struct Blob { Blob(Blob&&){} }; // Copy constructor deleted.
struct Object {};
enum MyEnum {x, y, z};
enum HerEnum {xx, yy, zz};
int main() {
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral>::type b;
b.print(); // int short char long Thing double Blob MyEnum Object float HerEnum
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum>::type c;
c.print(); // int short char long MyEnum HerEnum Thing double Blob Object float
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum, std::is_arithmetic>::type d;
d.print(); // int short char long MyEnum HerEnum double float Thing Blob Object
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum, std::is_arithmetic, std::is_member_pointer, std::is_copy_constructible>::type e;
e.print(); // int short char long MyEnum HerEnum double float Thing Object Blob
}
问题是试图优化上面的代码。
PartitionWithUnaryPredicate<Pack, First>
被计算了两次,我正在尝试定义只使用一次的 JoinSpecial
。但是我无法得到正确的语法。
template <template <typename, template <typename> class> class Pack, typename... Ts>
struct JoinSpecial : Join<typename Pack::head, typename MultipartitionWithUnaryPredicates<typename Pack::tail, Ts...>::type> {};
不编译。模板类型 PartitionWithUnaryPredicate
是类型 template <typename, template <typename> class> class
是吗?
更新:
感谢 Angew 的提示,我现在的语法正确了:
template <template <typename, template <typename> class> class P, typename Pack, template <typename> class Pred, template <typename> class... Ts>
struct JoinSpecial : Join<typename P<Pack, Pred>::head, typename MultipartitionWithUnaryPredicates<typename P<Pack, Pred>::tail, Ts...>::type> {};
template <typename Pack, template <typename> class First, template <typename> class... Rest>
struct MultipartitionWithUnaryPredicates<Pack, First, Rest...> : JoinSpecial<PartitionWithUnaryPredicate, Pack, First, Rest...> {};
现在一切正常——我第一次使用 template-template-templates,我必须说它看起来很丑。
在您对 JoinSpecial
的定义中,Pack
是一个 class 模板。然后,在为 Join
指定模板参数时,您有 typename Pack::head
和 typename Pack::tail
。但是 Pack
是一个模板,而不是 class — 您需要为 Pack
.
提供模板参数
我正在写一个元函数MultipartitionWithUnaryPredicates
,用于表单
MultipartitionWithUnaryPredicates<Pack<Args...>, UnaryPredicates...>::type
因此,类型模板包将由一元谓词包 UnaryPredicates...
进行多分区,分区按照列出的一元谓词的顺序进行。如果您不确定我的意思,请查看下面代码中的 main()(它工作正常):
#include <iostream>
#include <type_traits>
#include <typeInfo>
template <template <typename> class, typename, typename, typename> struct Helper;
template <template <typename> class UnaryPredicate, template <typename...> class P, typename... Types1, typename... Types2>
struct Helper<UnaryPredicate, P<>, P<Types1...>, P<Types2...>> {
using type = P<Types1..., Types2...>;
using head = P<Types1...>;
using tail = P<Types2...>;
};
template <template <typename> class UnaryPredicate, template <typename...> class P, typename First, typename... Rest, typename... Types1, typename... Types2>
struct Helper<UnaryPredicate, P<First, Rest...>, P<Types1...>, P<Types2...>> : std::conditional<UnaryPredicate<First>::value,
Helper<UnaryPredicate, P<Rest...>, P<Types1..., First>, P<Types2...>>,
Helper<UnaryPredicate, P<Rest...>, P<Types1...>, P<Types2..., First>>
>::type {};
template <typename, template <typename> class> struct PartitionWithUnaryPredicate;
template <template <typename> class UnaryPredicate, template <typename...> class P, typename... Ts>
struct PartitionWithUnaryPredicate<P<Ts...>, UnaryPredicate> : Helper<UnaryPredicate, P<Ts...>, P<>, P<>> {};
template <typename, template <typename> class...> struct MultipartitionWithUnaryPredicates;
template <typename Pack, template <typename> class UnaryPredicate>
struct MultipartitionWithUnaryPredicates<Pack, UnaryPredicate> : PartitionWithUnaryPredicate<Pack, UnaryPredicate> {};
template <typename, typename> struct Join;
template <template <typename...> class P, typename... Types1, typename... Types2>
struct Join<P<Types1...>, P<Types2...>> {
using type = P<Types1..., Types2...>;
};
//template <template <typename, template <typename> class> class Pack, typename... Ts>
//struct JoinSpecial : Join<typename Pack::head, typename MultipartitionWithUnaryPredicates<typename Pack::tail, Ts...>::type> {};
template <typename Pack, template <typename> class First, template <typename> class... Rest>
struct MultipartitionWithUnaryPredicates<Pack, First, Rest...> : Join<typename PartitionWithUnaryPredicate<Pack, First>::head, typename MultipartitionWithUnaryPredicates<typename PartitionWithUnaryPredicate<Pack, First>::tail, Rest...>::type> {};
// The above can be improved, since PartitionWithUnaryPredicate<Pack, First> is being computed twice.
// -----------------------------------------------------------------------------------------------------------------------------------------------
// Testing:
template <typename...> struct Pack {};
template <typename Last>
struct Pack<Last> {
static void print() {std::cout << typeid(Last).name() << std::endl;}
};
template <typename First, typename ... Rest>
struct Pack<First, Rest...> {
static void print() {std::cout << typeid(First).name() << ' '; Pack<Rest...>::print();}
};
struct Thing {};
struct Blob { Blob(Blob&&){} }; // Copy constructor deleted.
struct Object {};
enum MyEnum {x, y, z};
enum HerEnum {xx, yy, zz};
int main() {
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral>::type b;
b.print(); // int short char long Thing double Blob MyEnum Object float HerEnum
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum>::type c;
c.print(); // int short char long MyEnum HerEnum Thing double Blob Object float
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum, std::is_arithmetic>::type d;
d.print(); // int short char long MyEnum HerEnum double float Thing Blob Object
MultipartitionWithUnaryPredicates<Pack<int, Thing, double, short, Blob, char, MyEnum, long, Object, float, HerEnum>,
std::is_integral, std::is_enum, std::is_arithmetic, std::is_member_pointer, std::is_copy_constructible>::type e;
e.print(); // int short char long MyEnum HerEnum double float Thing Object Blob
}
问题是试图优化上面的代码。
PartitionWithUnaryPredicate<Pack, First>
被计算了两次,我正在尝试定义只使用一次的 JoinSpecial
。但是我无法得到正确的语法。
template <template <typename, template <typename> class> class Pack, typename... Ts>
struct JoinSpecial : Join<typename Pack::head, typename MultipartitionWithUnaryPredicates<typename Pack::tail, Ts...>::type> {};
不编译。模板类型 PartitionWithUnaryPredicate
是类型 template <typename, template <typename> class> class
是吗?
更新: 感谢 Angew 的提示,我现在的语法正确了:
template <template <typename, template <typename> class> class P, typename Pack, template <typename> class Pred, template <typename> class... Ts>
struct JoinSpecial : Join<typename P<Pack, Pred>::head, typename MultipartitionWithUnaryPredicates<typename P<Pack, Pred>::tail, Ts...>::type> {};
template <typename Pack, template <typename> class First, template <typename> class... Rest>
struct MultipartitionWithUnaryPredicates<Pack, First, Rest...> : JoinSpecial<PartitionWithUnaryPredicate, Pack, First, Rest...> {};
现在一切正常——我第一次使用 template-template-templates,我必须说它看起来很丑。
在您对 JoinSpecial
的定义中,Pack
是一个 class 模板。然后,在为 Join
指定模板参数时,您有 typename Pack::head
和 typename Pack::tail
。但是 Pack
是一个模板,而不是 class — 您需要为 Pack
.