为什么我们需要模板模板参数的模板特化
Why do we need a template specialization for a template-template parameter
以这段代码为例,确定类型列表的长度:
template <class... Types>
class type_list {};
template <class TypeList>
struct type_list_length; // <---
template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
static constexpr std::size_t value = sizeof...(Types);
};
为什么我们需要标记声明?我尝试在几个编译器中编译没有它的代码,但总是出错。
简短的回答是,如果没有主模板,我们就无法编写专业化。
较长的答案是:如何在没有专门化的情况下从模板化类型的实例化中提取 Types...
?你不能。
尝试一下:
template <template <class...> class type_list, class... Types>
struct type_list_length
{
static constexpr std::size_t value = sizeof...(Types);
};
我们可以做到:
type_list_length<type_list, int, double, float>::value
但不是这个:
using MyListType = type_list<int, double, float>;
type_list_length<MyListType>::value;
因为我们的模板需要一个 template-template 参数和一些类型,所以我们被迫只接受一个类型来匹配 MyListType
:
template <class T>
struct type_list_length
{
static constexpr std::size_t value = // ????;
};
但现在我们面临着另一个问题。我们如何分配value
?我们需要一些方法来提取 MyListType
或至少计数的模板参数。
我们需要一种方法来匹配单一类型 和 它模板化的参数。因此,我们只需要匹配一个类型及其模板参数。
template <class TypeList>
struct type_list_length;
template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
static constexpr std::size_t value = sizeof...(Types);
};
第一个(不完整的)类型是我们的主要模板。它允许我们开始匹配单一类型,比如 MyListType
.
第二种(完整)类型是我们的专精。它允许我们匹配单个类型,如果它是模板化类型,则匹配用作它的模板参数的类型。
通过让第一个类型不完整,我们表明我们打算只允许专业化有效。
But why do we need the specialization in the first place?
因为你使用class
如下
std::cout << type_list_length<type_list<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argument
或
std::cout << type_list_length<std::tuple<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argumen
或以类似的方式。
观察模板参数:在这两种情况下都是类型; type_list<int, long, long long>
在第一种情况下,std::tuple<int, long, long long>
.
因此您不能将 type_list_length
声明为接收 template-template 类型
template <template <class...> class type_list, class... Types>
struct type_list_length // <--- doesn't work
{
static constexpr std::size_t value = sizeof...(Types);
};
因为你应该调用它传递一个 template-template 参数,后跟一个可变的模板列表;我的意思是......你应该按如下方式使用它
std::cout << type_list_length<type_list, int, long, long long>::value;
std::cout << type_list_length<std::tuple, int, long, long long>::value;
但是,这样一来,您就失去了 class 的能力:提取并计算类型参数的模板参数。
所以你需要先声明type_list_length
作为接收类型
template <typename> // no template parameter name needed here (not used)
struct type_list_length;
然后声明并定义一个特化,以防接收到的类型是带有参数
的template-template
template <template <typename...> class type_list, typename... Types>
struct type_list_length<TypeList<Types...>>
{ // ...................^^^^^^^^^^^^^^^^^^ the parameter is a type
static constexpr std::size_t value = sizeof...(Types);
};
以这段代码为例,确定类型列表的长度:
template <class... Types>
class type_list {};
template <class TypeList>
struct type_list_length; // <---
template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
static constexpr std::size_t value = sizeof...(Types);
};
为什么我们需要标记声明?我尝试在几个编译器中编译没有它的代码,但总是出错。
简短的回答是,如果没有主模板,我们就无法编写专业化。
较长的答案是:如何在没有专门化的情况下从模板化类型的实例化中提取 Types...
?你不能。
尝试一下:
template <template <class...> class type_list, class... Types>
struct type_list_length
{
static constexpr std::size_t value = sizeof...(Types);
};
我们可以做到:
type_list_length<type_list, int, double, float>::value
但不是这个:
using MyListType = type_list<int, double, float>;
type_list_length<MyListType>::value;
因为我们的模板需要一个 template-template 参数和一些类型,所以我们被迫只接受一个类型来匹配 MyListType
:
template <class T>
struct type_list_length
{
static constexpr std::size_t value = // ????;
};
但现在我们面临着另一个问题。我们如何分配value
?我们需要一些方法来提取 MyListType
或至少计数的模板参数。
我们需要一种方法来匹配单一类型 和 它模板化的参数。因此,我们只需要匹配一个类型及其模板参数。
template <class TypeList>
struct type_list_length;
template <template <class...> class type_list, class... Types>
struct type_list_length<TypeList<Types...>>
{
static constexpr std::size_t value = sizeof...(Types);
};
第一个(不完整的)类型是我们的主要模板。它允许我们开始匹配单一类型,比如 MyListType
.
第二种(完整)类型是我们的专精。它允许我们匹配单个类型,如果它是模板化类型,则匹配用作它的模板参数的类型。
通过让第一个类型不完整,我们表明我们打算只允许专业化有效。
But why do we need the specialization in the first place?
因为你使用class
如下
std::cout << type_list_length<type_list<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argument
或
std::cout << type_list_length<std::tuple<int, long, long long>>::value;
// ...........................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- template argumen
或以类似的方式。
观察模板参数:在这两种情况下都是类型; type_list<int, long, long long>
在第一种情况下,std::tuple<int, long, long long>
.
因此您不能将 type_list_length
声明为接收 template-template 类型
template <template <class...> class type_list, class... Types>
struct type_list_length // <--- doesn't work
{
static constexpr std::size_t value = sizeof...(Types);
};
因为你应该调用它传递一个 template-template 参数,后跟一个可变的模板列表;我的意思是......你应该按如下方式使用它
std::cout << type_list_length<type_list, int, long, long long>::value;
std::cout << type_list_length<std::tuple, int, long, long long>::value;
但是,这样一来,您就失去了 class 的能力:提取并计算类型参数的模板参数。
所以你需要先声明type_list_length
作为接收类型
template <typename> // no template parameter name needed here (not used)
struct type_list_length;
然后声明并定义一个特化,以防接收到的类型是带有参数
的template-templatetemplate <template <typename...> class type_list, typename... Types>
struct type_list_length<TypeList<Types...>>
{ // ...................^^^^^^^^^^^^^^^^^^ the parameter is a type
static constexpr std::size_t value = sizeof...(Types);
};