The general issue is why does this compile:
#include <cstddef>
template<typename T>
std::size_t size() { return sizeof(T); }
struct x;
template std::size_t size<x>();
// Or an implicit instantiation like:
int main() { return size<x>(); }
struct x {};
even though the definition of x
appear after the explicit instantiation? It seems like the instantiation means that sizeof(x)
is used with an incomplete type x
.
If it is replaced with a specialization (or with a non-template), it fails to compile as expected:
#include <cstddef>
template<typename T>
constexpr std::size_t size() { return sizeof(T); }
struct x;
template<> std::size_t size<x>() {
return sizeof(x); // error: invalid application of 'sizeof' to incomplete type 'x'
}
struct x {};
What gives? For context, this arose because standard libraries use sizeof(T)>0
as a "is T
complete" check, but T
can be completed after the check and it will still pass.