What you want at all cannot be done.
Removing a construct from T&& is reasonable, but T&& will not convert to T& unless T is const . This does not allow the case of a function argument.
You can use a different type for the version of the function argument than the version of the local variable.
A more general option is to build from a universal reference and possibly save a copy if your argument is rvalue.
template<class T> struct view_type_t { std::optional<T> possible_copy; T* ptr; view_type_t(T& t):ptr(std::addressof(t)) {} view_type_t(T&& t): possible_copy(std::forward<T>(t)), ptr(std::addressof(*possible_copy)) {} view_type_t() = delete;
this emulates the extension of the link life cycle, where the temporary lifetime is extended by the link. Such a Reference behaves like a bare rvalue reference in C ++.
Now Reference ref2 = 42; works, and now this is a link to a local copy of 42 .
I find this technique better than an alternative when you create other types of views, like backwards_range , which stores a copy of its original range if it is rvalue and does not have lvalue.
This allows:
for( auto&& x : backwards( std::vector<int>{1,2,3} ) )
work. More generally, if a vector was created as temporary, returned by a function, we can call back and transfer it directly; without creating a local copy, we are faced with life-time problems, because extending the lifetime does not commute.
Of course, for the above code to work, you need to replace std::optional (e.g. boost::optional ) outside of C ++ 17.