I feel like std::is_trivially_constructible<T, Arg> isn't telling me the truth. First, context:
I have a small-vector class, VectorND<T, N>. Default-constructing it default-constructs its members, so VectorND<float, 2>{} == VectorND<float, 2>{float{}, float{}} == VectorND<float, 2>{0.f, 0.f}. This is the desired behavior.
However, sometimes, for perf-critical code, I want to construct them uninitialized. My thought was that I could use a tag type like so:
struct uninitalized_t {};
static constexpr uninitalized_t uninitalized;
...
VectorND(uninitalized_t) {}
...
VectorND<float, 2> x{uninitalized}; //< Tell x to be uninitialized.
I can get that to work. First, if I do
template <typename T, std::size_t N>
class VectorND {
std::array<T, 2> x;
public:
VectorND() = default;
T& operator[](std::size_t i) { return x[i]; }
};
https://godbolt.org/z/oTvo33xEb
then the default constructor leaves the data uninitialized. Same with if it's VectorND() {}.
If I make it VectorND() : x{} {} then the data is zeroed, making it no longer trivially constructible, as expected. This is the desired default behavior.
But if I add explicit VectorND(uninitalized_t) {}, then VectorND<float, 2> x{uninitialized} does appear to be uninitialized: https://godbolt.org/z/j9KWhPT7n This is again what I want. But for some reason, std::is_trivially_constructible_v<VectorND<float, 2>, uninitalized_t> is false. Why? I've tried
VectorND() = default; // Or VectorND() {};
explicit VectorND(uninitalized_t) {}
and
VectorND() = default; // Or VectorND() {};
explicit VectorND(uninitalized_t) : VectorND() {}
I still get std::is_trivially_constructible_v<VectorND<float, 2>, uninitalized_t> == false. https://godbolt.org/z/3n1Mz9dWd
Why?