: 템플릿에 들어오는 타입이 다른 함수로 전달될때 타입의 변경 없이 완벽한 타입을 유지하면서 보내게 하는 것을 perfect foward 완벽한 전달이라고 한다.
보편참조를 통해 함수로 보내지는 객체들의 타입이 변경되지 않는다.
: 레퍼런스 충돌을 통해서
template <typename T>void f2(T& a) {}
int main()
{
int n;
f2<int>( ?? ) //가)번. f2( int & a) -> f2(int &a)
f2<int&>( ?? ); //나)번. f2( int& & a) -> f2(int &a)
f2<int&&>( ?? ) //다)번. f2( int&& & a) -> f2(int &a)
}
template <typename T>void f2(T& a) {}
int main()
{
int n;
f2(10); // error 발생함.
f2(n);
}
: template에서 템플릿 인자에 참조가 1개 붙어있을 때, 인자는 반드시 lvalue만 들어올 수 있음.
-> 외우는 것이 아니라 참조 충돌 알고 있으면 생각해낼 수 있다.
: template형식에서 함수 인자에 레퍼런스 연산자가 2개로 이루어져 있다면
함수의 인수로 lvalue, rValue 모두 받을 수 있는 참조 방식.
lvalue를 인자로 전달하면 lvalue ref로 결정됨.
rvalue를 인자로 전달하면 rvalue ref로 결정됨.
-> 함수 인자가 아닌, 템플릿 인자를 통해 함수 결정됨.
template<typename T> void func(T&& a) {}
int main()
{
int n = 10;
func<int>(10); // 가) func(int && ) -> func(int&&) 로 결정됨.
// 따라서 함수 인자로 rvalue 보내야 함.
func<int&>(n); // 나) func(int& && ) -> func(int &)
// 따라서 함수 인자를 lValue로 보내야 함.
func<int&&>(10); // 다)func(int&& && ) -> func(int &&) 결정됨
// 따라서 함수인자를 rValue로 보내야 함.
// 2개 호출하는 것 이외에도 여러 상황 조합해서 확인해보자.
// 함수 어떻게 결정되는지
//func<int&> (10); //-> error
// func<int>(n) ; //-> error
}
-> 함수의 타입에 따라 함수 결정.
lvalue 전달시 T(타입)는 lvalue 참조 로 결정됨.
rvalue 전달시 T(타입)는 rvalue로 결정됨 .
foo(n) => 컴파일러가 보기엔, 함수인자로 lValue가 왔기 때문에,
// 템플릿 인자인 T를 int& 로 결정됨.
foo(10) => 컴파일러가 보기엔 , 함수 인자로 rValue가 왔기 때문에,
// 템플릿 인자인 T를 int로 결정됨.
void f1(int & a){}
void f2(int &&a) {}
template <typename T> void f3(T& a){]
template <typename T> void f4(T&& a){]
\
\
\
\
\
\
\
정답은
f1은 lvalue
f2는 rValue
f3는 lValue
f4는 rValue , lvalue
f4의 경우는 템플릿 타입이 명시될 경우, 템플릿 인자에 따라 함수의 인자 타입이 제한됨. 뭘까용???
아래의 코드 Test 클래스는 포워딩 레퍼런스가 아님.
template<typename T> void foo(T&& a) {}
template<typename T> class Test
{
public:
void goo(T&& a) {} // forwarding reference ????
};
int main()
{
int n = 10;
foo(n); // ok
foo(10);// ok
Test<int> t1; // 객체 선언이후 바로 void goo(int&& a)함수 타입이 정해짐.
t1.goo(n); // error
t1.goo(10); // ok
Test<int&> t2; // T int& => void goo( int& && a) => void goo(int& )
t2.goo(n); // ok
t2.goo(10); // error
}
template<typename T> class Test
{
public:
void goo(T&& a) {} // forwarding reference 아님.
template<typename U> void hoo(U&& a) {} // forwarding reference
};
: 이것도 보편 참조임. 모던 이펙티브 24 참고.
: 보편 참조가 적용되는 것은 template 함수가 호출될때마다 형식 연역이 이루어져야하는 것을 말함.
클래스 템플릿의 경우에는 객체가 생성될때 이미 연역이 이루어지기 때문에 위 처럼 작성해야 함.
vector에서의 push_back은 오버로딩 되어 있고,
emplace_back 은 보편 참조임.