为什么 template<classTp> bool is_array<Tp[]> 是 template<class T> bool is_array<Tp> 的偏特化?
Why is template<classTp> bool is_array<Tp[]> a partial specialization for template<class T> bool is_array<Tp>?
如何理解 template<typename Tp> bool is_array<Tp[]> = true
是 template<typename T> bool is_array<Tp> = true
的偏特化?
这是相关的code snippet:
#include<iostream>
template<typename T>
bool is_array = false;
template<typename Tp>
bool is_array<Tp[]> = true;
int main()
{
std::cout << is_array<int> << std::endl;
std::cout << is_array<int[]> << std::endl;
}
我还注意到,一般来说,部分模板特化中的模板参数数量少于主模板中的模板参数数量。
偏特化通常看起来像 this:
#include<iostream>
template<typename T, typename U>
class add
{
public:
add(T x, U y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
template<typename U>
class add<int, U>
{
public:
add(int x, U y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main()
{
add<int, double>(1, 5.0);
add<char, int>('a', 9);
}
这是编译器为您的代码生成的中间输出(参考 cppinsights)
编译器正在使用数组的专用模板。
template<typename T>
bool is_array = false;
template<>
bool is_array<int> = false;
template<>
bool is_array<int []> = true;
template<typename Tp>
bool is_array<Tp[]> = true;
int main()
{
std::cout.operator<<(is_array<int>).operator<<(std::endl);
std::cout.operator<<(is_array<int []>).operator<<(std::endl);
}
现在如果删除下面的代码
template<typename Tp>
bool is_array<Tp[]> = true;
编译器会生成
template<typename T>
bool is_array = false;
template<>
bool is_array<int> = false;
template<>
bool is_array<int []> = false;
int main()
{
std::cout.operator<<(is_array<int>).operator<<(std::endl);
std::cout.operator<<(is_array<int []>).operator<<(std::endl);
}
你可以看到编译器只是简单地将T
替换为int[]
,这只不过是你提供的第二个模板,一个专门的模板。
要使模板成为 主要 的专业化,它需要比主要的更专业。这基本上意味着专业化必须匹配主要可以匹配的类型的严格子集。
在您的情况下,特化会匹配 int[]
、char[]
等。主要也会匹配这些类型,但主要会另外匹配 int
、char
、std::vector<std::string>
等
当像这样 is_array<int[]>
指定模板参数时,规则规定首先尝试专业化。在这种情况下,Tp[]
可以匹配到 int[]
(基本上是用 int
代替 Tp
),因此选择了专业化。
当指定这样的模板参数时 is_array<int>
,首先尝试特化,但匹配失败。然后尝试了主要模板,并且匹配,因此选择了主要模板。
正如您所提到的,通常情况下专业化具有较少的模板参数。这不是必需的,只要我上面提到的规则适用,即特化必须匹配主要可以匹配的类型的严格子集。
事实上,特化甚至可以比主有更多的模板参数。同样,要求只是专业化匹配主要匹配的类型的子集。
专业化甚至可以比主要有更多的模板参数。这是一个 example:
#include<iostream>
template<typename T>
bool is_array = false;
template <typename Tp, int N>
bool is_array<Tp[N]> = true;
int main()
{
std::cout << is_array<int> << std::endl;
std::cout << is_array<int[5]> << std::endl;
}
如何理解 template<typename Tp> bool is_array<Tp[]> = true
是 template<typename T> bool is_array<Tp> = true
的偏特化?
这是相关的code snippet:
#include<iostream>
template<typename T>
bool is_array = false;
template<typename Tp>
bool is_array<Tp[]> = true;
int main()
{
std::cout << is_array<int> << std::endl;
std::cout << is_array<int[]> << std::endl;
}
我还注意到,一般来说,部分模板特化中的模板参数数量少于主模板中的模板参数数量。
偏特化通常看起来像 this:
#include<iostream>
template<typename T, typename U>
class add
{
public:
add(T x, U y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
template<typename U>
class add<int, U>
{
public:
add(int x, U y)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main()
{
add<int, double>(1, 5.0);
add<char, int>('a', 9);
}
这是编译器为您的代码生成的中间输出(参考 cppinsights)
编译器正在使用数组的专用模板。
template<typename T>
bool is_array = false;
template<>
bool is_array<int> = false;
template<>
bool is_array<int []> = true;
template<typename Tp>
bool is_array<Tp[]> = true;
int main()
{
std::cout.operator<<(is_array<int>).operator<<(std::endl);
std::cout.operator<<(is_array<int []>).operator<<(std::endl);
}
现在如果删除下面的代码
template<typename Tp>
bool is_array<Tp[]> = true;
编译器会生成
template<typename T>
bool is_array = false;
template<>
bool is_array<int> = false;
template<>
bool is_array<int []> = false;
int main()
{
std::cout.operator<<(is_array<int>).operator<<(std::endl);
std::cout.operator<<(is_array<int []>).operator<<(std::endl);
}
你可以看到编译器只是简单地将T
替换为int[]
,这只不过是你提供的第二个模板,一个专门的模板。
要使模板成为 主要 的专业化,它需要比主要的更专业。这基本上意味着专业化必须匹配主要可以匹配的类型的严格子集。
在您的情况下,特化会匹配 int[]
、char[]
等。主要也会匹配这些类型,但主要会另外匹配 int
、char
、std::vector<std::string>
等
当像这样 is_array<int[]>
指定模板参数时,规则规定首先尝试专业化。在这种情况下,Tp[]
可以匹配到 int[]
(基本上是用 int
代替 Tp
),因此选择了专业化。
当指定这样的模板参数时 is_array<int>
,首先尝试特化,但匹配失败。然后尝试了主要模板,并且匹配,因此选择了主要模板。
正如您所提到的,通常情况下专业化具有较少的模板参数。这不是必需的,只要我上面提到的规则适用,即特化必须匹配主要可以匹配的类型的严格子集。
事实上,特化甚至可以比主有更多的模板参数。同样,要求只是专业化匹配主要匹配的类型的子集。
专业化甚至可以比主要有更多的模板参数。这是一个 example:
#include<iostream>
template<typename T>
bool is_array = false;
template <typename Tp, int N>
bool is_array<Tp[N]> = true;
int main()
{
std::cout << is_array<int> << std::endl;
std::cout << is_array<int[5]> << std::endl;
}