가변인자 템플릿
가변인자 템플릿
#include <iostream>
// 가변인자 템플릿. c++11 기술
template<typename ... Types>
void foo(Types ... args) {}
// 가변인자 클래스 템플릿
template<typename ... Types>
class Test {};
int main() {
foo(1);
foo(1, 3.3); // Types: int, double
// args: 1, 3.3
Test<int> t1;
Test<int, double> t2;
}
#include <iostream>
// 가변인자 템플릿. c++11 기술
template<typename ... Types>
void goo(Types ... args) {
std::cout<<"goo"<<std::endl;
}
void hoo(int a, double d, char c) {
std::cout<<"hoo"<<std::endl;
}
void joo(int *a, double *d, char *c) {
std::cout<<"joo"<<std::endl;
}
// Types: 여러개의 타입을 가지고 있는 타입의 집합
// args: 여러개의 값을 가지고 있는 인자 집합: parameter pack
template<typename ... Types>
void foo(Types ... args) {
// parameter pack 안에 인자 개수를 알고 싶다면
std::cout<<sizeof...(args)<<std::endl;
std::cout<<sizeof...(Types)<<std::endl;
// parameter pack 을 다른 함수로 전달하는 방법
goo(args...);
hoo(args...);
joo(&args...);
}
int main() {
foo(1, 3.3, 'a'); // 3
// 3
// goo
// hoo
// joo
}
#include <iostream>
int n = 0;
// 인자가 없는 경우
// 재귀를 멈출 오버로딩 함수가 먼저 정의되어 있어야 한다. 구현은 아래에 가능
// 이 함수를 아래. foo 밑에 정의하면 컴파일 error.
void foo() {}
// 인자 값을 꺼내려면 1번째 인자는 이름이 있는 변수로 받아야 한다.
// 결국 아래 template 은 foo() 함수를 4개 만들어 낸다.
template<typename T, typename... Types>
void foo(T value, Types... args) {
++n;
std::cout<<n<<" "<<typeid(T).name()<<": "<<value<<std::endl;
foo(args...); // args: 3.3, 'a', "hello"
// args: 'a', "hello"
// args: "hello"
// args:
}
int main() {
foo(1, 3.3, 'a', "hello"); // value: 1, args: 3.3, 'a', "hello"
// 1 i: 1
// 2 d: 3.3
// 3 c: a
// 4 PKc: hello
}
#include <iostream>
template<typename T, typename... Types>
class xtuple : public xtuple<Types...> {
public:
T value;
xtuple() {}
xtuple(const T& a, Types... args) : value(a), xtuple<Types...>(args...) {}
enum { N = xtuple<Types...>::N + 1 };
};
// 이미 xtuple이 위에 있으므로, 새로운 xtuple 을 만들지 않고 부분 전문화 해야 한다.
// template<typename T> class xtuple: 새로운. xtuple
template<typename T>
class xtuple<T> { // 부분 전문화 버전
public:
T value;
xtuple() {}
xtuple(const T& a) : value(a) {}
enum { N = 1 };
};
template<typename T>
int xtuple_size(T& a) {
return T::N;
}
// xtuple 의 N 번째 요소의 타입을 알아내는 방법: 어렵다.
// 이 경우, primary 버전은 사용되지 않고 부분전문화 버전만 사용된다.
// 이 경우, 구조체 몸체{} 없이 선언만 있어도 된다.
// 단 선언 자체는 꼭 있어야 부분 전문화 버전을 만들 수 있다.
template<int N, typename T>
struct xtuple_type;
// 0 번째 를 요구 할 때를 위한 부분 전문화
template<typename T, typename... Types>
struct xtuple_type<0, xtuple<T, Types...>> {
typedef T type;
typedef xtuple<T, Types...> tuple_type;
};
// 0 이 아닌 경우
template<int N, typename T, typename... Types>
struct xtuple_type<N, xtuple<T, Types...>> {
typedef typename xtuple_type<N - 1, xtuple<Types...>>::type type;
typedef typename xtuple_type<N - 1, xtuple<Types...>>::tuple_type tuple_type;
};
// xtuple_type 을 확인하기 위한 함수
// VC 에서는 이 함수가 컴파일 잘 되는데 gcc 에서는 안된다...?
template<int N, typename T>
void print_type(const T& a) {
std::cout << typeid(xtuple_type<N, T>::type).name() << std::endl;
}
// xtuple 값을 받아오기 위함 함수
template<int N, typename T>
auto xget(T& tp) { // auto == xtuple_type<N, T>::type& 이어야 할거같은데, xtuple_type 을 넣으면 컴파일 에러가 난다;
return static_cast<typename xtuple_type<N, T>::tuple_type>(tp).value;
}
int main() {
xtuple<int, char, double, short> t4(1, 'c', 3.3, 4);
std::cout << xtuple_size(t4) << std::endl; // 4
print_type<1>(t4); // char
std::cout << typeid(xtuple_type<0, xtuple<int, char, double, short>>::type).name() << std::endl;
// gcc 에서 이건 또 된다.
// 함수 내부랑 컴파일 했을때 T 타입이 완전히 동일한데 왜 함수안에선 안되는지 모르겠다;
std::cout << xget<1>(t4) << std::endl; // c
}
댓글남기기