codenuri 강석민 강사 강의 내용기반으로 정리한 내용입니다.
get using variadic template #1
기반 클래스에 멤버에 접근 하는 방법
- 기반 클래스의 멤버와 파생클래스의 멤버의 이름이 동일 할 때는 자신(파생클래스)의 멤버가 우선시 된다.
- 기반 클래스의 멤버에 접근하는 방법
- d.Base::value
- static_cast<Base&>(d).value;
- 값 캐스팅과 참조 캐스팅
- static_cast
(d): 임시 객체 생성 lvalue 가 될 수 없다. - static_case<Base&>(d): 임시객체를 생성 안함. lvalue 가 될 수 있다.
- static_cast
#include <iostream>
using namespace std;
struct Base
{
int value = 10;
}
struct Derived : public Base
{
int value = 20;
}
int main()
{
Derived d;
cout << d.value << endl; // 20
cout << d.Base::value << endl; // 10
cout << static_cast<Base>(d).value << endl; // 10 -> 임시 객체의 10임
cout << static_cast<Base&>(d).value << endl; // 10
static_cast<Base>(d).value = 30; // error (lvalue 가 될 수 없음)
static_cast<Base&>(d).value = 30; // ok
}
tuple의 요소에 접근하는 get 만들기
- tuple 이 0번째 요소는 자기 자신이 보관한다.
- tuple 의 N번째 요소는 N번째 기반 클래스가 저장 한다.
- N번째 요소의 타입과 N번째 요소를 저장하는 타입(N번째 기반 클래스 타입)을 알아야 한다.
#include <iostream>
using namespace std;
template<typename ... Types> struct xtuple
{
static constexpr int N = 0;
}
template<typename T, typename ... Types> struct xtuple<T, Types...> : public xtuple<Types...>
{
T value;
xtuple() = default;
xtuple(const T& v, const Types& ... args) : value(v), xtuple<Types...>(args...) {}
static constexpr int N = xtuple<Types...>::N + 1;
}
int main()
{
xtuple<int, double, char> t3(1, 3.4, 'A');
cout << t3.value << endl; // 1
// cout << static_cast<기반클래스&>(t3).value << endl;
cout << static_cast<xtuple<double, char>&>(t3).value << endl; // 3.4
cout << static_cast<xtuple<char>&>(t3).value << endl; // A
char c = xget<2>(t3);
}
template<size_t N, typename TP> // TP는 튜플
튜플TP의 N번째 요소의 타입&
xget(TP& tp)
{
return static_cast<TP의 N번째 기반클래스&>(tp).value;
}
get using variadic template #2
int main()
{
tuple_element<1, tuple<int, double, char>>::type n;
cout << typeid(n).name() << endl;
}
tuple_element
1.tuple이 가진 N 번째 요소의 타입을 구하는 템플릿
2.primary template 을 만든다. -> 의도적으로 선언만 할 수도 있다.
3.0번째 요소를 구하는 부분 특수화를 만든다.
#include <iostream>
using namespace std;
template<typename ... Types> struct xtuple
{
static constexpr int N = 0;
}
template<typename T, typename ... Types> struct xtuple<T, Types...> : public xtuple<Types...>
{
T value;
xtuple() = default;
xtuple(const T& v, const Types& ... args) : value(v), xtuple<Types...>(args...) {}
static constexpr int N = xtuple<Types...>::N + 1;
}
template<size_t N, typename TP> struct xtuple_element
{
typedef TP type;
}
// 요소의 타입을 구할 수 있도록 부분 특수화를 제공한다.
template<typenmae T, typename ... Types> struct xtuple_element<0, xtuple<T, Types...>>
{
typedef T type;
}
int main()
{
xtuple_element<0, xtuple<int, double, char>>::type n;
cout << typeid(n).name() << endl;
}
int 출력되는 것 확인가능함
4.N번째 요소를 위한 부분 특수화를 만들고, Recursive를 사용한다.
#include <iostream>
using namespace std;
template<typename ... Types> struct xtuple
{
static constexpr int N = 0;
}
template<typename T, typename ... Types> struct xtuple<T, Types...> : public xtuple<Types...>
{
T value;
xtuple() = default;
xtuple(const T& v, const Types& ... args) : value(v), xtuple<Types...>(args...) {}
static constexpr int N = xtuple<Types...>::N + 1;
}
template<size_t N, typename TP> struct xtuple_element;
// 요소의 타입을 구할 수 있도록 부분 특수화를 제공한다.
template<typenmae T, typename ... Types> struct xtuple_element<0, xtuple<T, Types...>>
{
typedef T type;
}
template<size_t N, typenmae T, typename ... Types> struct xtuple_element<N, xtuple<T, Types...>>
{
typedef typename xtuple_element<N-1, xtuple<Types...>>::type type;
}
int main()
{
xtuple_element<2, xtuple<int, double, char>>::type n;
cout << typeid(n).name() << endl;
}
char 출력됨
최종적으로 get 만들기
#include <iostream>
using namespace std;
template<typename ... Types> struct xtuple
{
static constexpr int N = 0;
}
template<typename T, typename ... Types> struct xtuple<T, Types...> : public xtuple<Types...>
{
T value;
xtuple() = default;
xtuple(const T& v, const Types& ... args) : value(v), xtuple<Types...>(args...) {}
static constexpr int N = xtuple<Types...>::N + 1;
}
template<size_t N, typename TP> struct xtuple_element;
// 요소의 타입을 구할 수 있도록 부분 특수화를 제공한다.
template<typenmae T, typename ... Types> struct xtuple_element<0, xtuple<T, Types...>>
{
typedef T type; // 0번째 요소의 타입
typedef xtuple<T, Types...> tupleType; // 0번째 요소를 저장하는 타입
}
template<size_t N, typenmae T, typename ... Types> struct xtuple_element<N, xtuple<T, Types...>>
{
typedef typename xtuple_element<N-1, xtuple<Types...>>::type type;
typedef typename xtuple_element<N-1, xtuple<Types...>>::tupleType tupleType;
}
template<size_t N, typename TP>
typename xtuple_element<N, TP>::type& xget(TP& tp)
{
return static_cast<typename xtuple_element<N, TP>::tupeType&>(tp).value;
}
int main()
{
xtuple<int, double, char> t3(1, 3.4, 'A'); // 0번째 요소의 타입 : int, 0번째 요소를 저장하는 타입 : xtuple<int, double, char>
// xtuple_element<2, xtuple<int, double, char>>::type n; // char
// xtuple_element<2, xtuple<int, double, char>>::tupleType t; // tuple<char>
xget<1>(t3) = 1.1;
cout << xget<1>(t3) << endl; // 1.1
}
print tuple
#include <iostream>
#include <tuple>
using namespace std;
int main()
{
tuple<int, int, int> tp(1,2,3);
print_tuple(tp); // 1,2,3
}
int x[] = {get<0>(tp), get<1>(tp)}; // get이 tuple의 개수에 따라…(get 은 template 이여서 컴파일 타임 상수로 해결해야함) -> index_sequence
#include <iostream>
#include <tuple>
using namespace std;
template<size_t ... N> struct index_sequence{};
/*
template<typename TP> void print_tuple(const TP& tp)
{
int x[] = {get<0>(tp), get<1>(tp)}; // get이 tuple의 개수에 따라...(get 은 template 이여서 컴파일 타임 상수로 해결해야함)
for(auto& n : x)
cout << n << ", ";
}
*/
template<typename TP, size_t ... I> void print_tuple(const TP& tp, index_sequence<I>& ) // I: 0, 1, 2
{
int x[] = {get<I>(tp)...}; // get<0>(tp), get<1>(tp), get<2>(tp)
for(auto& n : x)
cout << n << ", ";
}
int main()
{
tuple<int, int, int> tp(1,2,3);
print_tuple(tp, index_sequence<0,1,2>()); // 1,2,3
}
사용할 때 매번 index_sequence 넘겨야 하는 불편함…
C++11 make sequence 존재 -> make_index_sequence
#include <iostream>
#include <tuple>
using namespace std;
// template<size_t ... N> struct index_sequence{};
template<typename TP, size_t ... I> void print_tuple_imp(const TP& tp, index_sequence<I>& ) // I: 0, 1, 2
{
int x[] = {get<I>(tp)...}; // get<0>(tp), get<1>(tp), get<2>(tp)
for(auto& n : x)
cout << n << ", ";
}
template<typename TP> void print_tuple(const TP& tp) // I: 0, 1, 2
{
print_tuple_imp(tp, make_index_sequence<tuple_size<TP>::value>());
}
int main()
{
tuple<int, int, int> tp(1,2,3);
// print_tuple(tp, make_index_sequence<3>()); // 1,2,3
print_tuple(tp);
}
컴파일타임 상수를 가변인자로 받아낼 수 있는 것이 핵심!