I don't understand your problem with QString, but anyway, AFAIK the common way to get Unicode support with std::string is ICU. ICU is quite large (~15-20 MB binary) and it breaks binary compatibility with every release.
And QString had no magic to it other than wrapping its underlying data in ytf-16 which std::u16string does too.
It's not perfect but it gets the job done, IIRC.