tl;dr: Use freestanding functions.
First of all - std::string is kind of a mess, and has too many methods as-is. It's bad design to lump functionality into a class which doesn't need to be in that class, and can easily be implemented using simpler, more basic class methods - as a freestanding function.
Moreover - std::string is at the same time unwieldy to manipulate (it's not a string buffer or an std::stringstream), and not impossible to manipulate, i.e. not immutable.
But coming back to my earlier point: The "right way" - if there is any - to do what you wanted is with freestanding functions. For example, suppose you want to randomly permute the contents of an std::string. Well, either:
std::string& jumble(std::string& str)
or
std::string jumble(std::string str)
or maybe, if you want to feel cool and micro-optimized,
std::string jumble(const std::string& str)
std::string jumble(std::string&& str)
depending if you want to use strings more as immutable or as mutable entities.
Also remember, that we don't really have a single std::string class - we have a template based on the character type (and an allocator etc.), so if you want to be generic, you have to accept this class:
template<
class CharT,
class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>
> class basic_string;
PS - If we had uniform call syntax, like Bjarne proposed - which we really should IMHO - your freestanding functions could simply be invoked as though they were members:
auto jumbled = my_string.jumble();
std::stringinstead. Bonus points if they are generic and work with other containers too.