Как мы можем создавать шаблонные функции со ссылочным типом?
С++ не создает шаблоны, скажем T = Hoge&
.
Минимальный пример:
-
hoge.h
:
#include<cstdio>
class Hoge
{
public:
Hoge()
: hoge(0)
{
}
~Hoge()
{
}
int hoge;
void print() { printf("%d\n", hoge); }
};
template<typename T>
void f(T a);
-
hoge.cpp
:
#include "hoge.h"
template<typename T>
void f(T a)
{
a.print();
}
template void f<Hoge &>(Hoge &a);
-
main.cpp
:
#include "hoge.h"
int main(void)
{
Hoge h;
f(h);
return 0;
}
Я скомпилировал их с помощью g++ -std=c++11 main.cpp hoge.cpp
. Но это дает ошибку компоновщика:
Undefined symbols for architecture x86_64:
"void f<Hoge>(Hoge)", referenced from:
_main in aa-e35088.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Затем я изменил f(h)
в main.cpp
на f<Hoge &>
, и ошибка исчезла.
Почему f<Hoge &>(Hoge &)
не вызывается в первом случае?
В этом случае я могу избежать ошибок, набирая f<Hoge &>
каждый раз. Но, когда дело доходит до перегруженных операторов, это не может быть сделано.
Скажите, пожалуйста, как решить эту ошибку.
Ответы
Ответ 1
Компилятор попытается вывести самый простой шаблон T
. Здесь T=Hoge
отлично, поэтому компилятор не пытается обработать более сложные формы.
Вы можете четко указать свои намерения. Попробуйте следующее:
template<typename T>
void f(T& a);
T
по-прежнему будет выводиться как Hoge
, но ваша функция f
получит ссылку.
Это позволяет читателю ясно видеть это непосредственно в прототипе f
.
Когда дело доходит до вычитания аргумента шаблона, существует множество правил, возникающих под капотом компилятора. Когда я заявляю, что компилятор выводит простейший T, я действительно режу углы. Вот жизнеспособный источник: cppreference
Ответ 2
Вы можете создать экземпляр функции с ссылочным типом только так, как вы это делали. Однако компилятор не выводит аргумент шаблона в качестве ссылочного типа. Вы можете убедиться, что вы можете создать экземпляр шаблона функции OK, не предоставив компилятору аргумент, но указав аргумент:
f<Hoge&>(h);
Если вы хотите получить ссылочный тип, вы должны использовать ссылку пересылки в качестве аргумента своего шаблона функции:
template <typename T>
void f(T&& a);
При использовании ссылки пересылки в качестве аргумента шаблона и передачи аргумента Hoge
аргумент выводится в соответствии с категорией значений аргумента:
Hoge h;
Hoge const c;
f(h); // T becomes Hoge&
f(c); // T becomes Hoge const&
f(Hoge()); // T becomes Hoge