如何使用可变模板来转发类型和值模板参数?
How do I use variadic templates to forward both type and value template parameters?
假设我们有 3 种类型(S1、S2 和 S3):
//type 1 (good type)
template<typename T1, typename T2, typename T3>
struct S1{};
//type 2 (good type)
template<typename T1, typename T2, typename T3, int T4>
struct S2{};
//type 3 (bad type)
template<typename T1, typename T2, typename T3>
struct S3{};
//any other type is also a "bad type"
我们想创建一个类型特征来确定类型是 S1 还是 S2。
为简洁起见,我们使用可变参数模板,因为 T# 的细节不是很重要:
//a type trait to determine if a type is either "type 1" or "type 2"
//We expect ::value to be true if we can match either type.
//false otherwise.
//*ignore cv-qualifier related details
template <typename T> struct test:std::false_type{};
template <typename... Args> struct test<S1<Args...>>:std::true_type{};
template <typename... Args> struct test<S2<Args...>>:std::true_type{};
如果我们要测试这个类型特征,我们会发现它不适用于 S2:
std::cout << std::boolalpha;
std::cout << test<S1<int,int,int>>::value << '\n';
std::cout << test<S2<int,int,int,5>>::value << '\n';
std::cout << test<S3<int,int,int>>::value << '\n';
打印:
true
false
false
它不适用于 S2,因为已经定义了一种模板类型(在这种情况下,T4 已经是一个 int)。
是否可以使用可变参数模板以这种方式匹配所有模板类型?
不管它们是类型名称还是实际类型。
template <class A0,class A1, class A2, int x> struct test<S2<A0,A1,A2,x>>:std::true_type{};
一般来说,使用非类型模板参数进行元元编程是一件痛苦的事情。
考虑使用像 integral_constant
之类的东西,如果你做了很多的话:将值作为类型而不是作为值传递。您甚至可以将模板作为类型传递。
这是一个无需重新设计 S2 即可提供所需输出的解决方案:
#include <iostream>
#include <type_traits>
template<typename T1, typename T2, typename T3>
struct S1{};
//type 2 (good type)
template<typename T1, typename T2, typename T3, int T4>
struct S2{};
//type 3 (bad type)
template<typename T1, typename T2, typename T3>
struct S3{};
template <typename T> struct test : std::false_type{};
template <typename... Args> struct test<S1<Args...>> : std::true_type{};
template <template <typename, typename, typename, int> class P, typename A, typename B, typename C, int N>
struct test<P<A,B,C,N>> : std::conditional<
std::is_same<P<A,B,C,N>, S2<A,B,C,N>>::value,
std::true_type,
std::false_type
>::type {};
template <typename T1, typename T2, typename T3, int T4> struct S2Wannabe {};
int main() {
std::cout << std::boolalpha;
std::cout << test<S1<int,int,int>>::value << '\n'; // true
std::cout << test<S2<int,int,int,5>>::value << '\n'; // true
std::cout << test<S3<int,int,int>>::value << '\n'; // false
std::cout << test<S2Wannabe<int,int,int,5>>::value << '\n'; // false
}
但重新设计 S2 可能更容易解决您的问题。
假设我们有 3 种类型(S1、S2 和 S3):
//type 1 (good type)
template<typename T1, typename T2, typename T3>
struct S1{};
//type 2 (good type)
template<typename T1, typename T2, typename T3, int T4>
struct S2{};
//type 3 (bad type)
template<typename T1, typename T2, typename T3>
struct S3{};
//any other type is also a "bad type"
我们想创建一个类型特征来确定类型是 S1 还是 S2。
为简洁起见,我们使用可变参数模板,因为 T# 的细节不是很重要:
//a type trait to determine if a type is either "type 1" or "type 2"
//We expect ::value to be true if we can match either type.
//false otherwise.
//*ignore cv-qualifier related details
template <typename T> struct test:std::false_type{};
template <typename... Args> struct test<S1<Args...>>:std::true_type{};
template <typename... Args> struct test<S2<Args...>>:std::true_type{};
如果我们要测试这个类型特征,我们会发现它不适用于 S2:
std::cout << std::boolalpha;
std::cout << test<S1<int,int,int>>::value << '\n';
std::cout << test<S2<int,int,int,5>>::value << '\n';
std::cout << test<S3<int,int,int>>::value << '\n';
打印:
true
false
false
它不适用于 S2,因为已经定义了一种模板类型(在这种情况下,T4 已经是一个 int)。
是否可以使用可变参数模板以这种方式匹配所有模板类型?
不管它们是类型名称还是实际类型。
template <class A0,class A1, class A2, int x> struct test<S2<A0,A1,A2,x>>:std::true_type{};
一般来说,使用非类型模板参数进行元元编程是一件痛苦的事情。
考虑使用像 integral_constant
之类的东西,如果你做了很多的话:将值作为类型而不是作为值传递。您甚至可以将模板作为类型传递。
这是一个无需重新设计 S2 即可提供所需输出的解决方案:
#include <iostream>
#include <type_traits>
template<typename T1, typename T2, typename T3>
struct S1{};
//type 2 (good type)
template<typename T1, typename T2, typename T3, int T4>
struct S2{};
//type 3 (bad type)
template<typename T1, typename T2, typename T3>
struct S3{};
template <typename T> struct test : std::false_type{};
template <typename... Args> struct test<S1<Args...>> : std::true_type{};
template <template <typename, typename, typename, int> class P, typename A, typename B, typename C, int N>
struct test<P<A,B,C,N>> : std::conditional<
std::is_same<P<A,B,C,N>, S2<A,B,C,N>>::value,
std::true_type,
std::false_type
>::type {};
template <typename T1, typename T2, typename T3, int T4> struct S2Wannabe {};
int main() {
std::cout << std::boolalpha;
std::cout << test<S1<int,int,int>>::value << '\n'; // true
std::cout << test<S2<int,int,int,5>>::value << '\n'; // true
std::cout << test<S3<int,int,int>>::value << '\n'; // false
std::cout << test<S2Wannabe<int,int,int,5>>::value << '\n'; // false
}
但重新设计 S2 可能更容易解决您的问题。