template<typename T> void f3(T& arg) {}
int main()
{
int n = 0;
f3<int>(n); // T : int T& : int& f3(int& arg) 함수 생성
f3<int&>(n); // T : int& T& : int& & f3(int& arg) 함수 생성
f3<int&&>(n); // T : int&& T& : int&& & f3(int& arg) 함수 생성
}
template<typename T> void f3(T& arg) {}
int main()
{
int n = 0;
// T를 int, int&, int&& 뭘해도 rvalue를 받을 수 없음
// T를 int로 결정하고 함수를 생성하지만 컴파일 에러
f3(0); // error
// T가 int, int&, int&& 뭐든지 lvalue를 받을 수 있음
// T를 int로 결정
f3(n); // ok
}
결론, T&는 임의 타입의 lvalue만 전달 가능
template<typename T> void f4(T&& arg) {}
int main()
{
int n = 0;
// 1. 사용자가 템플릿 인자를 직접 전달하는 경우
f4<int>(0); // T=int T&&=int&& f4(int&& arg)
f4<int&>(n); // T=int& T&&=int& && f4(int& arg)
f4<int&&>(0); // T=int&& T&&=int&& && f4(int&& arg)
// 2. 사용자가 템플릿 인자를 전달하지 않은 경우
f4(n); // T=int& f4(int& arg)
f4(0); // T=int f4(int&& arg)
}
lvalue(n)를 받을 수 있는 함수가 생성되고,
rvalue(0)를 받을 수 있는 함수가 생성된다는 의미
int&: lvalue reference
int&&: rvalue reference
T&: lvalue reference
T&&: forwarding reference (universal reference)
템플릿 함수에서 생성된 함수의 모양을 확인해 보려면
컴파일러가 지원하는 매크로 사용 __FUNCSIG__
함수 템플릿을 만들 때 forwarding reference를 사용하면
lvalue와 rvalue를 각각 받을 수 있는 함수 생성
생성된 각 함수는 call by value가 아닌 call by reference를 사용해서 전달받음
call by value
인자로 전달된 객체의 복사본이 생성
void foo(int arg) {}
const lvalue reference
복사본은 생성되지 않지만 const 속성을 추가해서 가리킴
void foo(const int& arg) {}
lvalue 버전과 rvalue 버전의 함수를 따로 제공
복사본도 없고 const 속성도 추가되지 않음
함수 인자로 전달된 객체의 속성의 변화없이 받을 수 있음
void foo(int& arg) {}
void foo(int&& arg) {}
forwarding reference 사용
방법 3의 함수들을 컴파일러가 자동 생성
template<typename T> void foo(T&& arg) {}
forwarding reference의 의미
임의 타입의 lvalue와 rvalue를 복사본을 만들지 않고 속성의 변화 없이 그대로 받고 싶을 때 사용
forwarding reference가 활용되는 주된 분야
template<typename T> class Test
{
public:
void foo(T&& arg) {}
template<typename U> void goo(U&& arg) {}
};
int main()
{
int n = 0;
Test<int> t; // T=int로 이미 결정
// void foo(int&& arg)
// t.foo(n); // error
t.foo(0); // ok
t.goo(n);
t.goo(0);
}
int main()
{
int n = 0;
auto a1 = n; // ok
auto a2 = 0; // ok
auto& a3 = n; // ok
// auto& a4 = 0; // error
// auto 자리는 T로, 우변을 함수인자로 생각
// T&& arg = 함수인자
auto&& a5 = n; // auto=int& int& && a5 = n -> int& a5 = n
auto&& a6 = 0; // auto=int int && a6 = 0 -> int&& a6 = n
}