Reputation: 20780
I have next code:
#include <utility>
template<typename T>
struct fun
{
fun(T&&){}
fun(const T&){}
};
template<typename T>
fun<T> create_fun(T&& val)
{
return fun<T>(std::forward<T>(val));
}
template<typename T>
fun<T> create_fun(const T& val)
{
return fun<T>(val);
}
int main()
{
int i = 1;
const int ci = 2;
fun<int> a = create_fun<int>(1);
fun<int> b = create_fun<int>(i);
fun<int> c = create_fun<int>(ci);
fun<int> d = create_fun(1);
fun<int> e = create_fun(i);
//error: no viable conversion from fun<int&> to fun<int>
//why is create_fun(T&& val) a better match than create_fun(const T& val)?
fun<int> f = create_fun(ci);
return 0;
}
Can you please explain me why for non const lvalues the universal reference is a better match?
How may I achieve the same behaviour as the one from a
, b
and c
without explicitly specifying the type to create_fun
?
EDIT:
I want to force fun
to be generated with int as parameter for all 3 calls
#include <utility>
template<typename T>
struct fun
{
fun(T&&){}
};
template<typename T>
fun<T> create_fun(T&& val)
{
return fun<T>(std::forward<T>(val));
}
template<typename T>
struct show_type;
int main()
{
int i = 1;
const int ci = 2;
show_type<decltype(create_fun(1))>();
show_type<decltype(create_fun(i))>();
show_type<decltype(create_fun(ci))>();
return 0;
}
Upvotes: 2
Views: 231
Reputation: 137310
Given create_fun(i);
with a non-const lvalue i
, template argument deduction for the two competing overloads results in:
fun<T> create_fun(T&& val) ==> fun<int&> create_fun(int& val) (T = int &)
fun<T> create_fun(const T& val) ==> fun<int> create_fun(const int& val) (T = int)
The first one is a better match than the second by §13.3.3.2 [over.ics.rank]/3.1.6. So the first one is selected.
Instead of using two overloads, you can just use a single universal reference template, and remove reference and const
from T
in create_fun
's return type:
template<typename T>
using remove_cv_and_ref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template<typename T>
fun<remove_cv_and_ref_t<T>> create_fun(T&& val)
{
return fun<remove_cv_and_ref_t<T>>(std::forward<T>(val));
}
Demo.
Upvotes: 3