As other answers say, the calls are ambiguous because universal references T&&, U&&
match both lvalue- and rvalue-references. You can manually remove ambiguities using std::enable_if
, e.g.
template <bool C>
using only_if = typename std::enable_if <C>::type;
template <typename T>
using is_lref = std::is_lvalue_reference <T>;
struct X
{
template <typename T, typename U>
static void
Func3(T& t, U& u) { cout << "X1" << endl; }
template <typename T, typename U>
static only_if <!is_lref <T>()>
Func3(T&& t, U& u) { cout << "X2" << endl; }
template <typename T, typename U>
static only_if <!is_lref <U>()>
Func3(T& t, U&& u) { cout << "X3" << endl; }
template <typename T, typename U>
static only_if <!(is_lref <T>() || is_lref <U>())>
Func3(T&& t, U&& u) { cout << "X4" << endl; }
};
See also live example. This way you explicitly say T&&
should not match an lvalue-reference.
This approach is hard to generalize to more input arguments. In that case, consider processing only one argument at a time, leaving the remaining ones as rvalue-references. Thus you need only two overloads plus recursive calls, but the exact form depends on what you want to do.