这是一个演示(从cppreference简化):
#include <iostream>
#include <type_traits>
template<class T>
struct is_array : std::false_type {};
template<class T>
struct is_array<T[]> : std::true_type {};
class A {};
int main()
{
std::cout << std::boolalpha;
std::cout << is_array<A>::value << '\n';
std::cout << is_array<A[]>::value << '\n';
std::cout << is_array<A[3]>::value << '\n';
}
输出(live demo
):
false
true
false
我们可以看到is_array<A[3]>
被解析为主要专长:template<class T> struct is_array
,而不是template<class T> struct is_array<T[]>
。
这让我有些困惑。当然,我知道std::is_array
的完整实现(如cppreference中所述)也包含长度的特殊化:template<class T, std::size_t N> struct is_array<T[N]>
,而std::is_array<A[3]>
将按预期解析为这种特殊化。但这不能解释最上面的演示,对吗?
搜索后,我发现了this thread,但这是关于如何而不是为什么的问题。但是在comment中,@Steve Jessop提到:
我不确定,但是我认为您所写的内容专门用于未知大小的数组。这是一个不完整的类型,但是可以在其他TU将提供的数组的外部声明中使用。
它似乎与it being an incomplete type有关:
数组对象的声明类型可能是未知范围的数组,因此在翻译单元中的某个时刻是不完整的,并在以后完成;这两个点的数组类型(“ T的未知边界数组”和“ N T的数组”)是不同的类型。无法完成指向未知范围的数组的指针的类型或由typedef声明定义为未知范围的数组的类型
extern int arr[]; // the type of arr is incomplete
int arr[10]; // now the type of arr is complete
[basic.types]/6没有提供与此有关的任何其他有用信息。
我注意到规格样本中存在错误,这使我想到也许不是专业化,而是因为A[3]
无法匹配struct is_array<T[]>
。那就是编译器似乎要确认的:
#include <iostream>
#include <type_traits>
template<class T>
struct is_array<T[]> : std::true_type {};
class A {};
int main()
{
is_array<A[3]> *a; // error
is_array<A[3]> b; // error
}
以上是我自己尝试解决的问题,但没有成功。所以我在这里找到一个彻底答案。
答案 0 :(得分:3)
简短的答案是在您自己引用的段落中:
声明的数组对象类型可能是未知数组 绑定,因此翻译单元中的一点不完整 并在稍后完成; 这两点的数组类型(“ T的未知边界”和“ NT的数组”是不同的类型。方式 指向未知范围的数组的指针,或者由 typedef声明是一个未知范围的数组,不能是 完成
这些是不同的类型。尽管可以在声明的第一点之后“修复”数组 object 的类型,但仍然不会改变那些类型不同的事实。他们的行为有所不同。例如:
using AI = int[];
using AC = int[3];
AI a1 = {1, 2, 3, 4};
AC a2 = {1, 2, 3, 4}; // error
可以使用初始化器a1
初始化对象{1, 2, 3, 4}
。我们看到别名为AI
的类型的行为类似于auto
,可以使用初始化程序来推导完整的类型。
另一方面,a2
会导致错误,因为我提供了太多的初始化程序。而且,如果我提供的数据太少,则我的数组中仍将包含3个元素,其中未明确初始化的元素将被默认初始化。
我希望您现在已经确信这些确实是非常不同的类型。因此,作为模板参数,它们不匹配。