/* Just floating the idea, all and any feedback appreciated! :) --- Max */
This is a proposal to tighten the definition of std::move so that it would
not accept a const-qualified argument, and, therefore, never return a const
rvalue reference. Calling std::move with a const-qualified argument should
result in a compilation error, explaining that such a value is not movable.
Presumably, the intent of calling std::move is always to obtain a mutable
rvalue reference, never a const rvalue reference. Const rvalue references
in general only have corner case applications, e.g. by STL [1].
In all cases known to the author of the proposal, when std::move was called
with a const-qualified argument, it indicated a programmer's error. Usually
such an error does not lead to incorrect code, only to less efficient code,
because instead of a move-aware overload a copying overload of the called
function is used. But since move semantics is a performance-enabling feature,
it seems practical to prevent such ways to accidentally misuse std::move.
This will encourage correct and efficient use and reduce the number of
"gotchas" in the standard library.
Note that this proposal is a breaking change, because it reduces the set of
acceptable programs, but, if there are indeed no benefits from calling
std::move with a const-qualified value, then all the broken cases will be
incorrectly and inefficiently applied std::move calls. Hence this change
may uncover performance defects, but it will not break any "proper" calls,
which produce mutable rvalue references.
# std::move misuse cases this change will break/prevent.
1. std::move attempting to move from a const local variable.
2. std::move attempting to move from a const member field
during move construction.
3. Accidental mistake in move constructor signature leading to
an std::move attempting to move from a const rvalue:
class X {
private:
vector<int> m_v;
public:
X(const X&& other) : m_v(std::move(other.m_v)) { };
};
# Potential new implemenation of std::move.
template <typename T> constexpr remove_reference_t<T>&&
move(T&& t) noexcept
{
static_assert(!std::is_const<remove_reference_t<T>>::value,
"std::move does not accept const-qualified arguments");
return static_cast<remove_reference_t<T>&&>(t);
}
# References
[1] CppCon 2014: Stephan Lavavej "STL Features And Implementation
Techniques", minutes 41-47: