- everything should ideally be constexpr. The problem here is that constexpr requires initializing all elements, and this will heavily penalize runtime uses of f.ex. fixed_string<512>. On compilers with __builtin_is_constant_evaluated (gcc 9, clang 9) we should use that; otherwise, it might be worth it to create a specialization for N < some suitable upper limit.
Wait, I have an idea. template<std::size_t N> struct fixed_string { private: std::size_t size_ = 0; union { char first_ = 0; char data_[ N+1 ]; }; public: fixed_string() = default; }; Now default initialization sets just the first char to zero, as we want, and value initialization initializes all data_ to zero and is constexpr. auto f1() { fixed_string<24> s; return s; } auto f2() { constexpr fixed_string<24> s{}; return s; } https://godbolt.org/z/uhf4S4 I don't know if that's defined behavior or not, but if it isn't, it better be.