Why can templates that require a complete type be instantiated when the type is completed after the instantiation?

Viewed 52

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.

0 Answers
Related