The reason std::string(0) is valid, is due to 0 being a null pointer constant. So 0 matches the string constructor taking a pointer. Then the code runs afoul of the precondition that one may not pass a null pointer to std::string.
Only literal 0 would be interpreted as a null pointer constant, if it was a run time value in an int you wouldn’t have this problem (because then overload resolution would be looking for an int conversion instead). Nor is literal 1 a problem, because 1 is not a null pointer constant.
Since it’s a compile time problem (literal invalid values) you can catch it at compile time. Add an overload of this form:
void operator[](std::nullptr_t) = delete;
std::nullptr_t is the type of nullptr. And it will match any null pointer constant, be it 0, 0ULL, or nullptr. And since the function is deleted, it will cause a compile time error during overload resolution.