Given assign1<int>(r);, you're specifying the template argument explicitly, then the parameter type of assign1 would be int&&, as you said, it's rvalue-reference and can't be bound with lvalue.
Given assign2<int>(r);, you're specifying the 1st template argument A as int, the parameter pack Args will be deduced from the function argument r. Note that it's not rvalue-reference but forwarding reference, which could accpet both lvalues and rvalues. (Depending on the function arguments are lvalues or rvalues, according to the type deduction result, the function parameter type would be lvalue-reference or rvalue-reference.)
Given assign3<int>(r);, you're specifying only the 1st template argument A, but the 2nd parameter parameter B can't be deduced from function argument and the calling fails.
If you want to make the function template accepting rvalues only, you can add static_assert like
template<typename A, typename... Args>
void assign2(Args&& ...) {
static_assert(((!std::is_lvalue_reference_v<Args>) && ...), "must be rvalue");
}
LIVE
Or apply SFINAE.
template<typename A, typename... Args>
std::enable_if_t<((!std::is_lvalue_reference_v<Args>) && ...)> assign2(Args&& ...) {
}
LIVE
Or add another overload taking lvalue-references and mark it as delete. (This approach works only when all the arguments are lvalues.)
template<typename A, typename... Args>
void assign2(Args& ... arguments) = delete;
LIVE
assign1, you explicitly specify the parameter type, and the actual argument can't be converted to that type. Forassign2, you explicitly specifyA, butAisn't used for anything. Instead,Argsis automatically deduced from the argument type. - Igor Tandetnik