반응형

Parameter Pack 각 요소 꺼내기

  • Pack Expansion -> array or tuple에 담기
#include <iostream>
#include <tuple>
using namespace std;

template<typename ... Types> 
void foo(Types ... args)
{
    // 각각의 타입별 값을 tuple 개별 요소로 추가
    tuple<Types...> tp(args...);

    cout << get<0>(tp) << endl;
    cout << get<1>(tp) << endl;
    cout << get<2>(tp) << endl;
}


int main()
{
    foo(1, 3.4, "AA");
}

 

  • 재귀 호출과 유사한 호출식을 사용하기
    • 1번째 인자는 이름 있는 변수 2번째 인자는 가변 인자로 구현
#include <iostream>
#include <tuple>
using namespace std;

void foo() {} // 재귀 호출 종료용

template<typename T, typename ... Types>
void foo(T value, Types ... args)
{
    cout << value << endl;
    foo(args...); 
    // 아래처럼 반복 호출 됨
    // foo(3.4, "AA");
    // foo("AA");
    // foo();
}


int main()
{
    foo(1, 3.4, "AA"); // value : 1, args : 3.4, "AA"
}

 

 

fold expression(C++17)

  • 이항 연산자를 사용해서 parameter pack안에 있는 요소에 연산을 수행하는 문법
  • parameter pack의 이름에서 ... 붙이지 않고 사용
    • pack expansion : args...
    • fold expression : args + ...
  • 4가지 형태(args:1,2,3,4)
    • unary right fold: ( args op ... )
      • (args + ... ) // 1+(2+(3+4))
    • unary left fold : (... op args)
      • (... + args) // ((1+2)+3)+4
    • binary right fold : ( args op ... op init)
      • ( args + ... + 10) // 1+(2+3(4+10)))
    • binary left fold : ( init op ... op args)
      • (10 + ... + args) // (((10+1)+2)+3)+4
#include <iostream>
using namespace std;

template<typename ... Types>
void foo(Types ... args)
{

    // args 값을 모두 호출할 수 있음
    //binary left fold : ( init op ... op args)
    (cout << ... << args);
}

int main()
{
    foo(1, 2, 3);
    (((cout << 1) << 2) << 3);
}
#include <iostream>
#include <vector>
using namespace std;

vector<int> v;

template<typename ... Types>
void foo(Types ... args)
{
    (v.push_back(args), ...);
    for (auto n : v)
        cout << n << endl;
}

int main()
{
    foo(1, 2, 3);
    (((cout << 1) << 2) << 3);
}
반응형

반응형

함수의 리턴타입, 인자타입 정보를 구하는 traits 만들기

  • 메인 템플릿(Main template)을 만들고 typedef T type 제공(C++11 using 동일)

  • 부분 특수화(Partial specialization)를 통한 원하는 타입을 얻을 수 있도록 T 타입 분할

    • 함수 타입 T(double(short, int))를 리턴타입 double과 인자타입(short, int)로 분리

    • T(double(short, int)) -> R(A1, A2)

  • 메인 템플릿의 활용도가 없을 경우 내부 type은 제거 해도 됨

#include <iostream>
using namespace std;

double hoo(short a, int b) { return 0; }

// 반환 타입에 대한 메인 템플릿
template<typename T> 
struct result_type
{
    typedef T type;
};

// 함수타입에 대한 부분 특수화
template<typename T, typename A1, typename A2> 
struct result_type<T(A1, A2)>
{
    typedef T type;
};

// 인자는 복수개이므로 N 파라미터 추가로 필요
template<typename T, size_t N>
struct argument_type
{
    typedef T type;
};

// 첫번째 인자에 대한 부분 특수화
template<typename R, typename A1, typename A2>
struct argument_type<R(A1, A2), 0>
{
    typedef A1 type;
};

// 두번째 인자에 대한 부분 특수화
template<typename R, typename A1, typename A2>
struct argument_type<R(A1, A2), 1>
{
    typedef A2 type;
};

template<typename T> void foo(T& t)
{
    // T : double(short, int)
    typename result_type<T>::type ret_type;
    typename argument_type<T, 0>::type arg_type0;
    typename argument_type<T, 1>::type arg_type1;

    cout << typeid(ret_type).name() << endl; // double
    cout << typeid(arg_type0).name() << endl; // short
    cout << typeid(arg_type1).name() << endl; // int
}
int main()
{
    foo(hoo);
}

C++11 표준의 함수 리턴 타입 구하기

  • result_of(C++17 미만)
  • invoke_result(C++17 이상)
  • decltype 사용해서 구현(일반함수, 함수 객체, 람다표현식등의 모든 callable object 고려)

 

반응형

반응형

type traits 기능(C++11)

  • type에 대한 query : is_pointer<>, is_array<>, extent<>

  • type에 대한 변형 타입 : remove_pointer<>, add_pointer<>

#include <iostream>
#include <type_traits>
using namespace std;

template<typename T> void foo(T a)
{
    bool b = is_pointer<T>::value;
    typename remove_pointer<T>::type t;
    
    cout << typeid(t).name() << endl;
}

int main()
{
    int n = 10;
    foo(n);
    foo(&n);
}

 

remove_pointer 구현 예제

  • remove_pointer_custom 메인 템플릿 생성

    • int -> int 반환

  • remove_pointer_custom 부분 특수화(Partial specialization) 생성

    • int* -> int 반환

#include <iostream>
using namespace std;

// Main template
template<typename T> 
struct remove_pointer_custom
{
    typedef T type;
};

// Partial specialization
template<typename T> 
struct remove_pointer_custom<T*>
{
    typedef T type;
};

template<typename T> void foo(T a)
{
    // 값이 아닌 타입을 꺼낼때는 typename을 꼭 사용 필요
    typename remove_pointer_custom<T>::type t;

    cout << typeid(t).name() << endl;
}

int main()
{
    int n = 10;
    foo(&n);
}

 

remove_all_pointer 구현 예제

  • 중첩 포인터까지 모두 제거 되는 remove_pointer 구하는 방법
#include <iostream>
using namespace std;

template<typename T> 
struct remove_all_pointer_custom
{
    typedef T type;
};

template<typename T> 
struct remove_all_pointer_custom<T*>
{
    // 포인터 타입일때까지 포인터를 제거하며 자기 자신을 호출하고 최종 메인 템플릿이 호출됨
    typedef typename remove_all_pointer_custom<T>::type type;
};

int main()
{
    typename remove_all_pointer_custom<int**>::type n;
    cout << typeid(n).name() << endl;
}
반응형

+ Recent posts