The code doesn't violate the strict aliasing rule in any way. An lvalue of type const T is used to access an object of type T, which is permitted.
The rule in question, as covered by the linked question, is a lifetime rule; C++14 (N4140) [basic.life]/7. The problem is that, according to this rule, the pointer data+pos may not be used to manipulate the object created by placement-new. You're supposed to use the value "returned" by placement-new.
The question naturally follows: what about the pointer reinterpret_cast<T *>(data+pos) ? It is unclear whether accessing the new object via this new pointer violates [basic.life]/7.
The author of the answer you link to, assumes (with no justification offered) that this new pointer is still "a pointer that pointed to the original object". However it seems to me that it is also possible to argue that , being a T *, it cannot point to the original object, which is a std::aligned_storage and not a T.
This shows that the object model is underspecified. The proposal P0137, which was incorporated into C++17, was addressing a problem in a different part of the object model. But it introduced std::launder which is a sort of mjolnir to squash a wide range of aliasing, lifetime and provenance issues.
Undoubtedly the version with std::launder is correct in C++17. However, as far as I can see, P0137 and C++17 don't have any more to say about whether or not the version without launder is correct.
IMHO it is impractical to call the code UB in C++14, which did not have std::launder, because there is no way around the problem other than to waste memory storing all the result pointers of placement-new. If this is UB then it's impossible to implement std::vector in C++14, which is far from ideal.