C++ 템플릿 타입추론
타입 알아내는 방법
- typeid
- C++ 표준
- const, volatile, reference 인식 불가
- boost::type_index
- type_id_with_cvr
().pretty_name() - 변수는 decltype() 사용
- type_id_with_cvr
#include <iostream>
#include <boost\type_index.hpp>
using namespace std;
using namespace boost::typeindex;
template<typename F> void foo(const F f)
{
cout << "F : " << typeid(F).name() << endl;
cout << "f : " << typeid(f).name() << endl;
}
template<typename B> void bar(const B b)
{
cout << "B : " << type_id_with_cvr<T>().pretty_name() << endl;
cout << "b : " << type_id_with_cvr<decltype(a)>().pretty_name() << endl;
}
int main()
{
foo(3); // F : int, f : int
bar(3); // B : int, b : const int
}
template argument type deduction
- type decuction rule
- 컴파일러가 함수 인자를 보고 타입 결정
- 함수 인자의 타입과 완전히 동일한 타입으로 결정되지 않음
- 값 타입 foo(T t)
- const, volatile, reference 를 제거
- 인자가 가진 const 만 제거
- 참조 타입 Bar(T& t)
- reference 만 제거한다.
- const, volatile 은 유지
- const T& 의 경우 const 제거
- forwarding reference (T&& t)
- lvalue, rvalue 모두 전달 받음
- 배열
- argument decay 발생
template<typename T> void foo(T t)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
}
template<typename T> void bar(T& t)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
cout << type_id_with_cvr<decltype(t)>().pretty_name() << endl;
}
template<typename T> void car(const T& t)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
cout << type_id_with_cvr<decltype(t)>().pretty_name() << endl;
}
int main()
{
int n = 0;
int & r = n;
const int c = n;
const int& cr = c;
const char* s1 = "hello";
const char* const s2 = "world";
foo(n); // T = int
foo(c); // T = int
foo(r); // T = int
foo(cr); // T = int
foo(s1); // T = char const*
foo(s2); // T = char const*
bar(n); // T = int, t = int&
bar(c); // T = int const, t = int const&
bar(r); // T = int, t = int&
bar(cr); // T = int const, t = int const&
car(n); // T = int, t = int const&
car(c); // T = int, t = int const&
car(r); // T = int, t = int const&
car(cr); // T = int, t = int const&
}
= Array Name =
int n1; // 변수이름 = n, 타입 = int
int *pN = &n1;
int n2 = n1; // 모든 변수는 동일한 타입의 변수로 초기화(복사) 될 수 있다.
int arr1[3] = { 1, 2, 3 }; // 변수이름 = arr1, 타입 = int[3]
int arr2[3] = arr1; // error
// 배열의 이름은 첫번째 요소의 주소로 암시적 형변환 된다.
int *pArr0 = arr1; // 배열의 요소의 주소
int (*pArr1)[3] = &arr1; // 배열의 주소
// pArr0 + 1 => pArr0 + 4 // sizeof(int)
// pArr1 + 1 => pArr1 + 12 // sizeof(int[3])
*pArr0 = 10;
(*pArr1)[0] = 10;
- 크기가 다른 배열은 다른 타입
template<typename T> void foo(T a, T b) {}
template<typename T> void bar(T& a, T& b) {}
foo("22", "333"); // T = const char*
bar("22", "333"); // T = const char[] error
- argument decay
template<typename T> void foo(T t)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
cout << type_id_with_cvr<decltype(t)>().pretty_name() << endl;
}
template<typename T> void bar(T& t)
{
cout << type_id_with_cvr<T>().pretty_name() << endl;
cout << type_id_with_cvr<decltype(t)>().pretty_name() << endl;
}
int main()
{
int x[3] = { 1, 2, 3 };
int y[3] = x; // error
int *p = x; // ok
int (&r)[3] = x; // ok
//foo(x); // T = int[3] ? foo(int a[3]) => error
foo(x); // foo( int* )
// int*, int*
bar(x); // bar(int (&a)[3])
// int [3], int (&) [3]
}
class template type deduction
- C++17 부터 지원
- 생성자의 인자를 보고 결정
- class template type deduction guide
// C++17
template<typename T>
class Test
{
T data;
Test() {}
Test(T t) {}
template<typename C> Test(C& c) {}
}
// user define deduction guide, C++17
Test() -> Test<int>;
template <typename C>
Test(C& c) -> Test< typename C::value_type >;
// C = list<int>, C::value_type = int
int main()
{
Test<int> t1;
Test t2(10);
Test t3;
//list<int> l = { 1, 2, 3 };
list l = { 1, 2, 3 }; // C++17
Test t4(l);
}
Object Generator Idioms
- 클래스 템플릿의 객체를 생성하는 함수 템플릿
template<typename T> void foo(T t) {}
template<typename T, typename U> struct pair
{
T first;
U second;
pair(const T& t, const U& u) : first(t), second(u) {}
}
template<typename T, typename U>
pair<T, U> make_pair(const T& t, const U& u)
{
return pair<T, U>(t, u);
}
int main()
{
pair<int, double> p( 1, 3.14 );
foo(p);
foo( pair<int, double>(1, 3.14) );
foo( make_pair(1, 3.4) );
foo( pair(1, 3.4) ); // C++17, 우왕 편하다+_+
}
Identity
- 함수템플릿에서 컴파일러에 의한 타입 추론을 막음
- 사용자가 반드시 타입을 정하도록 함
template<typename T> struct identity
{
typedef T type;
}
template<typename T> void foo(T t) {}
template<typename T> void bar(typename identity<T>::type t) {}
int main()
{
identity<int>::type n; // int
foo(3);
foo<int>(3);
bar(3); // error
bar<int>(3);
}