There's been some progress on this question in C++23.
C++11 codified in the library the pre-existing best practice that "const means thread-safe."
C++23 finally codifies in the library the pre-existing best practice that "const means callable on rvalues" — specifically, "const-assignable means proxy reference."
A type such as tuple<int, int> continues to have the ordinary tuple& operator=(const tuple&). But a type such as tuple<int&, int&> — the return value of std::tie — now has const tuple& operator=(const tuple&) const, too. So that this works in C++23:
int i=1, j=2;
const auto tup = std::tie(i, j); // Note `const` here!
tup = std::make_tuple(j, i); // Proxy references are const-assignable
This means that we can finally distinguish types that are supposed to be rvalue-assignable (i.e., proxy-reference types like tuple<int&>) from types that are not supposed to be rvalue-assignable (i.e., all other types).
And that means that we can finally give a compiler warning whenever we see someone trying to assign to a non-const rvalue of a non-proxy-reference class type! I've implemented the diagnostic in my personal fork of Clang; it just needs someone (not me) to volunteer to upstream it into Clang trunk and/or GCC.
Here is your example (Godbolt), showing the new diagnostic:
<source>:5:17: warning: possibly unintended assignment to an rvalue of
type 'std::string' (aka 'basic_string<char>') [-Wassign-to-class-rvalue]
5 | std::string{} = "42";
| ~~~~~~~~~~~~~ ^
.../include/c++/v1/string:1270:69: note: declared here
1270 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const value_type* __s) {
| ^
In other words, we can get your desired compiler behavior today without changing the language specification at all. The compiler can detect this kind of bug, for people who want to detect it (should be almost everyone); without actually breaking old code for people with billion-line codebases, and without complicating the language spec with special cases for assignment.
The blog post goes into more detail about the complicated corner cases. For example, it's not just operator= that you'd care about, but also operator+= and postfix operator++... and what about prefix operator++, should we add a ref-qualifier to it too?... and so on. Moving the feature into a simple compiler diagnostic moots all those thorny questions; compiler vendors can iterate on the quality of their diagnostic without interacting with the language-standardization process.