Предположим, у вас есть следующая пара функций:
void f(const int&) {
// Do something, making a copy of the argument.
}
void f(int&&) {
// Do the same thing, but moving the argument.
}
Они довольно избыточны - единственная разница между функциями заключается в том, копируют ли они или перемещают свой аргумент.Конечно, мы можем добиться большего, переписав эту функцию в виде единого шаблона:
template<typename T>
void g(T&&) {
// Do something, possibly using std::forward to copy or move the argument.
}
Это работает, и на практике это часто используемая идиома.Но шаблон может быть создан в виде трех функций, по сравнению с нашими двумя выше.Мы можем убедиться, что это происходит с помощью следующего фрагмента кода:
#include <iostream>
template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";
template<typename T>
void g(T&&) {
std::cout << reinterpret_cast<void*>(&g<T>)
<< " = &g<" << type<T> << ">" << std::endl;
}
int main() {
int i = 0;
const int& cr = 0;
g(i);
g(cr);
g(0);
return 0;
}
/*
Prints:
0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/
Добавлена третья функция для случая, когда T = int&
, которого у нас не было, когда мы использовали нашу не шаблонную функциюf
выше.В этом случае нам на самом деле не нужна эта неконстантная справочная версия l-значения функции - учитывая, что f
было достаточно для наших первоначальных потребностей - и это увеличивает размер нашего кода, особенно если у нас много шаблонных функцийнаписаны таким образом, что вызывают друг друга.
Есть ли способ написать нашу функцию g
выше, чтобы компилятор автоматически выводил T = const int&
, когда g(i)
вызывается в нашем примере кода?То есть способ, при котором нам не нужно вручную писать g<const int&>(i)
, но все же получить желаемое поведение.