如何解决模板模板类型的计数参数
以下代码在GCC中有效(至少在GCC 10.1.0中有效),但不适用于MSVC和Clang。我不确定这在C ++标准中是否合法。
我正在尝试计算template template
类型的参数。
以下代码是否是有效的C ++代码,如果是,那么如何使它们在Clang和MSVC中工作,如果不是,是否有替代方法?
template <template<typename...> typename T>
struct template_count {
static constexpr unsigned value = 0;
};
template <template<typename> typename T>
struct template_count<T> {
static constexpr unsigned value = 1;
};
template <template<typename,typename> typename T>
struct template_count<T> {
static constexpr unsigned value = 2;
};
template <template<typename,typename,typename> typename T>
struct template_count<T> {
static constexpr unsigned value = 3;
};
template <typename one,typename two,typename three>
struct test {
};
int main() {
return template_count<test>::value;
}
解决方法
在twitter中某人的提示下,我找到了一种适用于GCC和Clang(Link to compiler explorer)(in github)的更好的解决方案:
#include <type_traits>
#include <cstddef>
struct variadic_tag {};
struct fixed_tag : variadic_tag {};
struct number_signature {};
template<std::size_t V>
struct ParameterNumber : number_signature {
constexpr static auto value = V;
};
template<typename T>
concept NumberObjConcept = std::is_base_of_v<number_signature,T>;
template<template<typename> typename>
auto DeduceArgs() -> ParameterNumber<1>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<2>;
template<template<typename,typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<3>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<4>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<5>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<6>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<7>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<8>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<9>;
template<template<typename,typename> typename>
auto DeduceArgs() -> ParameterNumber<10>;
template<template<typename...> typename F>
auto DeduceTemplateArgs(variadic_tag) -> ParameterNumber<1000000000>; // a meaningless big number
template<template<typename...> typename F>
auto DeduceTemplateArgs(fixed_tag) -> decltype(DeduceArgs<F>());
template <typename one,typename two,typename three>
struct test {
};
#define __DEDUCE_TEMPLATE_ARGS(c) decltype(DeduceTemplateArgs<c>(fixed_tag{}))
int main() {
return __DEDUCE_TEMPLATE_ARGS(test)::value;
}
当然上述代码在这种情况下会失败:
template <template<typename> typename>
struct test {};
在大多数情况下都可以。
,这使用基于值的元编程。
tag
(_t
)是表示类型的编译时间值。
template<class T>
struct tag_t { using type=T; };
template<class T,T t>
struct tag_t<std::integral_constant<T,t>>:std::integral_constant<T,t> { using type=T; };
template<class T>
constexpr tag_t<T> tag = {};
value
(_t
)是一个编译时值(和标记)。
template<auto x>
using value_t = tag_t<std::integral_constant<std::decay_t<decltype(x)>,x>>;
template<auto x>
constexpr value_t<x> value = {};
ztemplate
(_t
)<Z>
是表示模板的编译时间值。
template<template<class...>class Z,std::size_t N=0>
struct ztemplate_type : value_t<N>,ztemplate_type<Z,static_cast<std::size_t>(-1)> {};
template<template<class...>class Z>
struct ztemplate_type<Z,static_cast<std::size_t>(-1)>:
tag_t<ztemplate_type<Z,static_cast<std::size_t>(-1)>>
{
template<class...Ts>
constexpr tag_t<Z<Ts...>> operator()( tag_t<Ts>... ) const { return {}; }
};
template<template<class>class Z>
constexpr ztemplate_type<Z,1> ztemplate_map( ztemplate_type<Z>,int ) { return {}; }
template<template<class,class>class Z>
constexpr ztemplate_type<Z,2> ztemplate_map( ztemplate_type<Z>,class,3> ztemplate_map( ztemplate_type<Z>,int ) { return {}; }
template<template<class...>class Z>
constexpr ztemplate_type<Z> ztemplate_map( ztemplate_type<Z>,... ) { return {}; }
template<template<class...>class Z>
using ztemplate_t = decltype( ztemplate_map( ztemplate_type<Z>{},true ) );
template<template<class...>class Z>
constexpr ztemplate_t<Z> ztemplate = {};
请勿直接使用ztemplate_type
;使用ztemplate_t
和ztemplate
。
测试代码:
template<class> struct A {};
template<class,class> struct B {};
template<class,class> struct C {};
template<class,class> struct D {};
auto a = ztemplate<A>;
auto b = ztemplate<B>;
auto c = ztemplate<C>;
auto d = ztemplate<D>;
(void)a,(void)b,(void)c,(void)d;
auto a_v = a(tag<int>);
auto b_v = b(tag<int>,tag<double>);
auto c_v = c(tag<int>,tag<double>,tag<char>);
auto d_v = d(tag<int>,tag<char>,tag<void>);
(void)a_v,(void)b_v,(void)c_v,(void)d_v;
std::cout << a << b << c << "\n";
输出为:
123
在此范例中,ztemplate
是映射tag
的函数对象。这些tag
可以是ztemplate
或value
或包装原始类型。
您可以使用特定的模板实例。
template <typename T>
struct template_count { static constexpr unsigned value = 0; };
template <template<typename...> typename T,typename ... Args>
struct template_count<T<Args...>> { static constexpr unsigned value = sizeof...(Args); };
int main() {
static_assert(template_count<test<int,int,int>>::value == 3);
}
没有特定实例化的一般解决方案可能会遇到可变参数模板的问题。
template <typename ... T> struct test {};
int main() {
static_assert(template_count<test>::value == ????); //no solution
static_assert(template_count<test<int,int>>::value == 2);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。