What you're doing may be legal, but that depends on the real definition of class T, so we can't know for sure based on the code you've shown.
Starting with C++11 §3.9.2/3:
Pointers to incomplete types are allowed although there are restrictions on what can be done with them.
Those restrictions are listed in §3.2/4:
A class type T must be complete if:
- an object of type Tis defined, or
- a non-static class data member of type Tis declared, or
- Tis used as the object type or array element type in a new-expression, or
- an lvalue-to-rvalue conversion is applied to a glvalue referring to an object of type T, or
- an expression is converted (either implicitly or explicitly) to type T, or
- an expression that is not a null pointer constant, and has type other than void*, is converted to the type pointer toTor reference toTusing an implicit conversion, adynamic_castor astatic_cast, or
- a class member access operator is applied to an expression of type T, or
- the typeidoperator or thesizeofoperator is applied to an operand of typeT, or
- a function with a return type or argument type of type Tis defined or called, or
- a class with a base class of type Tis defined, or
- an lvalue of type Tis assigned to, or
- the type Tis the subject of analignofexpression, or
- an exception-declaration has type T, reference toT, or pointer toT.
The 6th bullet appears pertinent here, as we can see in §5.2.10/7 that a reinterpret_cast between pointer types is defined in terms of static_cast:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
But because reinterpret_cast static_casts to void* first, then to the real resulting pointer type, that 6th bullet doesn't apply.
So, so far you're still in legal territory, despite T being an incomplete type. However, if it turns out that T is not a standard-layout type or has stricter alignment requirements than int, then the last sentence in §5.2.10/7 holds true and you're invoking UB.