How to omit perfect forwarding for deduced parameter type?
SFINAE hidden in a template parameter list:
#include <type_traits>
template <typename T
, typename = typename std::enable_if<!std::is_lvalue_reference<T>{}>::type>
void f(T&& v);
template <typename T>
void f(const T& v);
DEMO
SFINAE hidden in a return type:
template <typename T>
auto f(T&& v)
-> typename std::enable_if<!std::is_lvalue_reference<T>{}>::type;
template <typename T>
void f(const T& v);
DEMO 2
In c++14 typename std::enable_if<!std::is_lvalue_reference<T>{}>::type
can be shortened to:
std::enable_if_t<!std::is_lvalue_reference<T>{}>
Anyway, even in c++11 you can shorten the syntax with an alias template if you find it more concise:
template <typename T>
using check_rvalue = typename std::enable_if<!std::is_lvalue_reference<T>{}>::type;
DEMO 3
With c++17 constexpr-if:
template <typename T>
void f(T&& v)
{
if constexpr (std::is_lvalue_reference_v<T>) {}
else {}
}
With c++20 concepts:
template <typename T>
concept rvalue = !std::is_lvalue_reference_v<T>;
void f(rvalue auto&& v);
void f(const auto& v);
DEMO 4
How about a second level of implementation:
#include <utility>
#include <type_traits>
// For when f is called with an rvalue.
template <typename T>
void f_impl(T && t, std::false_type) { /* ... */ }
// For when f is called with an lvalue.
template <typename T>
void f_impl(T & t, std::true_type) { /* ... */ }
template <typename T>
void f(T && t)
{
f_impl(std::forward<T>(t), std::is_reference<T>());
}
I think SFINAE should help:
template<typename T,
typename = typename std::enable_if<!std::is_lvalue_reference<T>::value>::type>
void f (T &&v) // thought to be rvalue version
{
// some behavior based on the fact that v is rvalue
auto p = std::move (v);
(void) p;
}
template <typename T>
void f (const T &v) // never called
{
auto p = v;
(void) p;
}