I have the following situation where I need to move construct t2 from t1.
Unfortunately it is not possible to do that (constness violation I suppose)
What is the right approach to handle that transparently from the caller of foo ? (ie. without requiring a passing by value and an explicit std::move)
struct T
{
T() = default;
~T() = default;
T(T&&) = default;
};
T foo(const T& t)
{
T t3;
if (predicate)
return t3;
else
return std::move(t);
}
int main()
{
T t1;
T t2 = foo(t1);
return 0;
}
You could do this if you wanted to badly enough. To do it, your foo
would end up as essentially a re-implementation of std::move
.
struct T
{
T() = default;
~T() = default;
T(T&&) = default;
};
template<class T> struct my_remove_reference {typedef T type;};
template<class T> struct my_remove_reference<T&> {typedef T type;};
// The third part of a normal `remove_reference`, but which we don't need in
// this case (though it'll all still be fine if you un-comment this).
//template<class T> struct my_remove_reference<T&&> {typedef T type;};
template <typename T>
typename my_remove_reference<T>::type &&foo(T &&t) {
return static_cast<typename my_remove_reference<T>::type &&>(t);
}
int main()
{
T t1;
T t2 = foo(t1);
return 0;
}
Now, despite the fact that you can/could do this, the other answers remain more or less correct -- even though you can do it, you almost certainly shouldn't. If you used this foo
on a real class that supports move construction (i.e., will really move the state from the source to the destination) you'd end up basically destroying your source object even though it remains visible.
Doing this with your edited question, where foo
could, but wouldn't always, destroy the source object would be particularly pernicious. With the right name that makes it clear that foo
really moves from the source, it could, possibly, be just barely reasonable to do this -- but (at least to me) a function that might or might not destroy its argument seems drastically worse than one that does so dependably. Obviously, a version of foo
like above that just does the same thing as std::move
is pointless, but a version that also did some other processing on the input (and, for whatever reason, couldn't be used along with std::move
) might, possibly, be just barely acceptable if you really didn't have any other choice.