如何使用可变参数模板转发类型和值模板参数?

时间:2016-02-26 00:03:27

标签: c++ templates c++14 variadic-templates sfinae

假设我们有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)。

是否可以使用可变参数模板以这种方式匹配所有模板类型?
无论是类型名称还是实际类型。

2 个答案:

答案 0 :(得分:4)

template <class A0,class A1, class A2, int x> struct test<S2<A0,A1,A2,x>>:std::true_type{};

通常,使用非类型模板参数的元元数据编程是一种痛苦。

如果您正在做很多事情,请考虑使用integral_constant之类的东西:将值作为类型而不是值传递。您甚至可以将模板作为类型传递。

答案 1 :(得分:1)

这是一个解决方案,可以提供您想要的输出,而无需重新设计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可能更容易解决您的问题。