作为模板类型参数,为什么type [N]不匹配其专门版本---- template <class t =“”> class S <t []>

时间:2018-06-20 14:18:12

标签: c++ templates language-lawyer specialization

这是一个演示(从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
}

demo


以上是我自己尝试解决的问题,但没有成功。所以我在这里找到一个彻底答案。

1 个答案:

答案 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个元素,其中未明确初始化的元素将被默认初始化。

我希望您现在已经确信这些确实是非常不同的类型。因此,作为模板参数,它们匹配。