Here is a demo (shortened from 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';
}
output(live demo
):
false
true
false
We can see that is_array<A[3]>
is resolved as the primary specialization: template<class T> struct is_array
, and not template<class T> struct is_array<T[]>
.
It confuses me a fair bit. Of course I know the complete implementation of std::is_array
(as documented in cppreference) also contains a specialization for length: template<class T, std::size_t N> struct is_array<T[N]>
, and std::is_array<A[3]>
will resolve to this specialization as expected. But that cannot explain the uppermost demo, right?
After searching, I found this thread, but it is a question about how, not why. But in a comment, @Steve Jessop mentioned:
I'm not entirely sure, but I think what you've written there is a specialization for arrays of unknown size. That's an incomplete type, but can be used in an extern declaration of an array that some other TU will provide.
It seems to related to it being an incomplete type:
The declared type of an array object might be an array of unknown bound and therefore be incomplete at one point in a translation unit and complete later on; the array types at those two points (“array of unknown bound of T” and “array of N T”) are different types. The type of a pointer to array of unknown bound, or of a type defined by a typedef declaration to be an array of unknown bound, cannot be completed
extern int arr[]; // the type of arr is incomplete
int arr[10]; // now the type of arr is complete
[basic.types]/6 doesn't offer any other useful information about this.
I noticed an error in the sample from the spec, which got me thinking that maybe it is not about specialization, but because A[3]
cannot match struct is_array<T[]>
. That's what the compiler seems to affirm:
#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
}
Above is what I tried to solve this by myself, without success. So I am here to find a thorough answer.