Руководство
Не перегружать:
template <typename T> void f(T&) {}
template <typename T> void f(T&&) {}
Причина
Для шаблона существует специальное правило удержания шаблона:
template <typename T> void f(T&&) {}
Это правило существует для того, чтобы разрешить так называемую "идеальную пересылку". Это помогает таким вещам, как bind
и make_shared
, полностью передавать свои аргументы, сохраняя как cv-квалификаторы, так и «категорию значений» (lvalue / rvalue-ness).
Это специальное правило гласит, что когда f(T&&)
вызывается с параметром lvalue (например, int
), то T выводится как ссылка lvalue (например, int&
) вместо int
. И ссылка rvalue на ссылку lvalue на int сворачивается до ссылки на lvalue на int. * Т.е. 1023 *
f(x)
звонки
f<int&>(int& && x);
, что упрощает до:
f<int&>(int& x);
Редактировать
Это не более или менее специализированный, чем f<int>(int&)
.
Спасибо Йоханнесу Шаубу за исправление (см. Комментарии).
Решение
Вы можете делать все, что захотите, с помощью одной функции:
template <typename T> void f(T&&) {}
Если T
выводит в качестве ссылки lvalue, делайте все, что вы хотели сделать при первой перегрузке, иначе делайте то, что вы хотели делать при второй перегрузке:
template <class T> void f_imp(T&, std::true_type) {std::cout << "lvalue\n";}
template <class T> void f_imp(T&&, std::false_type) {std::cout << "rvalue\n";}
template <typename T> void f(T&& x)
{
f_imp(std::forward<T>(x), std::is_lvalue_reference<T>());
}
И используйте std::forward
для полной пересылки x
в функцию детализации реализации.