반응형

함수 정보를 구하는 traits 만들기

  • 메인 템플릿(Primary template)을 만들고 typedef T type 제공

  • 함수 타입의 T안에 있는 리턴 타입을 얻을 수 있도록 부분 특수화 구현

  • 부분 특수화를 할땡 가변인자 템플릿을 활용

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

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

// 메인 템플릿
template<typename T>
struct result_type
{
    typedef T type;
};

// 함수 타입에 대한 부분 특수화, 가변인자 활용
template<typename T, typename ... Types>
struct result_type<T(Types ... args)>
{
    typedef T type;
};

template<typename T> void foo(const T& t)
{
    // T : double(short, int) 함수 모양
    typename result_type<T>::type ret;
    cout << typeid(ret).name() << endl;
}

int main()
{
    foo(hoo);
}

 

traits 잘못 사용할때 처리 방법

  • 메인 템플릿에서 typedef T type을 제공하지 않는 방법

  • 메인 템플릿에서 static_assert()를 사용해서 명시적 에러 메시지 출력

  • 메인 템플릿의 선언만 구현

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

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

// 1. typedef T type 미제공
template<typename T>
struct result_type
{
};

// 2. static_assert()를 사용해서 에러 메시지 출력
template<typename T>
struct result_type
{
    static_assert(is_function<T>::value, "Not supported type");
};

// 3. 선언부만 제공
template<typename T>
struct result_type;


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

template<typename T> void foo(const T& t)
{
    // T : double(short, int) 함수 모양
    typename result_type<T>::type ret;
    cout << typeid(ret).name() << endl;
}

int main()
{
    foo(hoo);
}
반응형

반응형

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);
}
반응형

반응형

가변인자 템플릿(Variadic template)

  • C++11부터 지원되는 문법

  • 가변인자 템플릿(클래스 템플릿, 함수 템플릿)의 기본 모양

  • 가변인자 템플릿의 인자 "Types"는 여러개의 타입을 나타냄

  • 가변인자 함수 템플릿의 인자인 "args"안에는 여러개의 값이 들어있고 "Parameter Pack"이라고 함

#include <iostream>
using namespace std;

// 가변인자 클래스 템플릿.
template<typename ... Types> class tuplex
{

};

// 가변인자 함수 템플릿
template<typename ... Types>
void foo(Types ... args)
{

}

int main()
{
    // 가변인자 클래스 템플릿(타입 생략, 복수의 타입까지...)
    tuplex<> t0p;
    tuplex<int> t1;
    tuplex<int, char> t2;
    
    // 가변인자 함수 템플릿(인자 생략, 복수의 인자까지...)
    foo();
    foo(1);
    foo(1, 3.4, "A");
}

Parameter Pack

  • 가변인자 템플릿으로 전달받은 파라미터 집합을 Parameter Pack이라 함

  • sizeof...(args), sizeof...(Types) 함수를 이용해서 Parameter Pack 요소의 갯수를 얻어 올 수 있음

  • goo(args...); 받은 Parameter Pack을 다시 전달할때 요소 전체를 풀어쓰는 방법을 Pack Expansion이라 함

#include <iostream>
using namespace std;

// Pack expansion을 통해 Parameter Pack을 전달 받을 함수
void goo(int n, double d, const char* s)
{
    cout << "goo : " << n << ", " << d << ", " << s << endl;
    // 1, 3.4, "AAA"
}

// 가변인자 함수 템플릿
template<typename ... Types>
void foo(Types ... args)
{
    // args : Parameter Pack
    
    cout << sizeof...(args) << endl; // 3
    cout << sizeof...(Types) << endl; // 3

    //goo(args); // Error
    goo(args...); // Pack expansion
                  // goo( 1, 3.4, "AAA")
}

int main()
{
    //foo();
    //foo(1);
    foo(1, 3.4, "AAA"); 
        // Types : int, double, const char*
        // args : 1, 3.4, "AAA"

}

Pack Expansion

  • Parameter Pack을 사용하는 패턴에 "..." 붙이면 해당 패턴이 ',' 구분자로 확장되는 형태임

  • args이 1, 2, 3을 가지고 있을때

    • args... -> 1, 2, 3 

    • (--args)... -> 0, 1, 2

    • func(args)... -> func(1), func(2), func(3)

    • func(args...) -> func(1, 2, 3)

    • func2(func(args...)) -> func2(func(1, 2, 3))

    • func2(func(args)...)) -> func2(func(1), func(2), func(3))

  • Pack Expansion은 함수 호출 인자 또는 list 초기화를 사용한 표현식에서만 사용할 수 있음

    • 배열 이용

      • 컴파일러에 따라 빈값이 허용 안될 수 있으므로 첫번째 요소를 더미로 0으로 지정

      • 함수가 반환 타입이 void 경우 대비해서 대체 반환값 (x, 0) 패턴 사용

        • int x[] = { 0, (print(args), 0)... };

    • 초기화 리스트 이용

      • 빈값이 허용 됨으로 배열에 비해서 첫번째 요소 더미 0을 생략 할 수 있음

      • initializer_list<int> e = { (print(args), 0)... };

#include <iostream>
using namespace std;

void goo(int n, double d, const char* s)
{
    cout << "goo : " << n << " " << d << " " << s << endl;
}

int hoo(int a) { return -a; }

int print(int a)
{
    cout << a << ", ";
    return 0;
}

template<typename ... Types>
void foo(Types ... args)
{
    int x[] = { args... }; // Pack expansion
    for (auto n : x)
        cout << n << endl;

    //print(args); // Error(함수 호출 인자 or list 초기화가 아님)
    //print(args...); // Error(함수 호출 인자 or list 초기화가 아님)
    //print(args)...; // Error(함수 호출 인자 or list 초기화가 아님)

    // 배열 이용
    int ea[] = { 0, (print(args), 0)... };

    // 초기화 리스트 이용
    initializer_list<int> ei = { (print(args), 0)... };

}

int main()
{
    foo(1, 2, 3);
     // Types : int, int, int
     // args : 1, 2, 3
}

 

Expansion 예제

#include <iostream>
using namespace std;

template<typename ... Types> void foo(Types ... args)
{
    // Types : int, double

    int x[] = { args... };
    pair<Types...> p1; // pair<int, double> // OK
    tuple<Types...> t1; // tuple<int, double> // OK

    tuple<pair<Types...>> t2; // tuple<pair<int, double>> // OK
    tuple<pair<Types>...> t3; // tuple<pair<int>, pair<double>> // Error

    tuple<pair<int, Types>...> t4; // tuple<pair<int, int>, pair<int, double>> // OK

    pair<tuple<Types...>> p2; // pair<tuple<int, double>> // Error
    pair<tuple<Types>...> p3; // pair<tuple<int>, tuple<double>> // OK

}

int main()
{
    foo(1, 3.4); 
      // args : 1, 3.4
      // Types : int, double
}
반응형

반응형

C++11 표준 type traits

  • 변형된 타입을 얻는 traits

    • typename remove_pointer<T>::type;

    • remove_pointer_t<T> n; // C++14

  • 타입의 정보를 조사하는 traits

    • bool b = is_pointer<T>::value;

    • bool b = is_pointer_v<T>;  // C++17

    • 함수 오버로딩 사용(true_type, false_type) 활용

  • 간소화된 버전

    • C++14 기본 제공

      • remove_pointer_t<T> n;

    • C++17 기본 제공

      • bool b = is_pointer_v<T>;

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

//using을 사용해서 간소화 가능
template<typename T>
using remove_pointer_type = typename remove_pointer<T>::type;

// C++17에서는 variable template을 사용해서 간소화 가능
//template<typename T>
//inline constexpr bool is_pointer_v = is_pointer<T>::value;

template<typename T> void foo(T a)
{
    // 포인터를 제거한 타입 반환
    typename remove_pointer<T>::type rawType;
    remove_pointer_type<T> rawType2;

    // 포인터 타입 여부 확인
    bool isPointer = is_pointer<T>::value;
}
int main()
{
    int n = 0;
    foo(&n);
}

 

C++11 표준 type_traits 예제

  • is_array<T>::value : 배열 확인

  • extent<T, 0>::value : 배열 각 차원의 요소 수 

  • is_same<T, U>::value : 타입 같음 비교

  • remove_cv<T, U>::type : const, volatile 속성 제거(타입 비교시 이용)

  • decay<T, U>::type : 배열을 포인터화 사용 필요 시

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

// 배열 정보 조사하기
// array => pointer : decay
template<typename T> void foo(T& a)
{
    if (is_array<T>::value)
    {
        cout << "array" << endl;

        cout << extent<T, 0>::value << endl;
        cout << extent<T, 1>::value << endl;
    }
}

template<typename T, typename U> void hoo(T a, U b)
{
    // 두 타입 비교
    bool ret1 = is_same<T, U>::value;

    // 배열일 경우 포인터화 비교
    bool ret2 = is_same<typename decay<T>::type, typename decay<U>::type>::value;

    // const, volatile 제거 후 비교
    bool ret3 = is_same<typename remove_cv<T>::type, typename remove_cv<U>::type>::value;

    cout << ret1 << endl;
    cout << ret2 << endl;
    cout << ret3 << endl;
}

int main()
{
    int x = 1;
    const int cx = 1;
    int* xp = &x;
    int a[3][2] = { 1,2,3,4,5,6 };
    foo(a);
    hoo(x, cx);
}
반응형

반응형

함수의 리턴타입, 인자타입 정보를 구하는 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;
}
반응형

반응형

integral_constant

  • 컴파일 타임에 결정된 상수 값을 별도 타입화 하여 함수 오버로딩을 할 수 있도록 만드는 int2type 기술
  • int2type 기술을 C++11에서 표준화한 integral_constant

기본 함수 오버로딩(Function overloading)

  • 이자의 개수가 다르거나 인자 타입이 다르면 아래와 같이 인수에 따라 서로 다른 함수가 호출 되게 할 수 있음

  • 인자가 개수가 같고 인자의 타입도 같을때 다른 함수가 되게 하려면?

#include <iostream>
using namespace std;

void foo(int n) {}
void foo(double d) {}

int main()
{
    foo(1); // foo(int)
    foo(1.2); // foo(double)
}

int2type

  • 컴파일 타임 정수형 상수를 각각의 독립된 타입으로 만드는 기술
  • int2type을 사용하면 컴파일 타임에 결정된 정수형 상수를 모두 다른 타입으로 만들 수 있음
    • 1, 2는 같은 타입이지만, int2type<1>, int2type<2>는 다른 타입
  • int2type을 함수 오버로딩에 사용하거나 템플릿 인자, 상속등에 사용할 수 있음
#include <iostream>
using namespace std;

// 같은 정수형 타입이지만 값에 따라 별도의 타입으로 생성
template<int N> struct int2type
{
    static constexpr int value = N;
};

int main()
{
    int2type<1> t0; // int2type<1> 타입
    int2type<2> t1; // int2type<2> 타입
}

int2type 예제

  • printv 함수에서 받은 값의 포인터 타입 여부에 따라 분기처리 코드가 작성되어 값과 포인터 참조값을 출력하도록 되어 있음

  • 포인터 여부는 컴파일 타임에 체크되지만 if 구문이 런타임 조건문으로 하위 코드들은 모두 컴파일 대상

  • 포인터가 아닌 값에 대해서는 사용할 수 없는 구분이 포함되어 간접 참조 에러가 발생함

  • 간접 참조 에러가 발생하는 구문을 별도의 함수 템플릿으로 분리함

  • 각 함수 템플릿은 int2type을 활용하여 인자 타입으로 구분하여 사용

  • 동일 이름을 가지는 함수가 여러개 있을때, 어느 함수를 호출할지는 컴파일 타임에 결정됨

  • 호출이 결정되지 않은 템플릿은 instantiation 되지 않음

#include <iostream>
using namespace std;

// 포인터 타입 체크용 메인 템플릿
template<typename T> struct is_pointer_custom
{
    //enum { value = false }; 
    static constexpr bool value = false; // c++11
};

// 포인터 타입에 대해서 부분 특수화 필요
template<typename T> struct is_pointer_custom<T*>
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};
...

// 같은 정수형 타입이지만 값에 따라 별도의 타입으로 생성되는 타입 도구
template<int N> struct int2type
{
    static constexpr int value = N;
};

// 컴파일 타임 상수 값 구분용 함수 템플릿
template<typename T>
void printv_imp(T v, int2type<1>)
{
    cout << v << " : " << *v << endl;
}

// 컴파일 타임 상수 값 구분용 함수 템플릿
template<typename T>
void printv_imp(T v, int2type<0>)
{
    cout << v << endl;
}

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template<typename T> void printv(T v)
{
    // 아래의 조건으로 분기 코드 작성시 if 구문이 런타임 조건문으로
    // 포인터가 아닌 값에 대해서 컴파일 에러 발생
    //if(is_pointer_custom<T>::value)
    //    cout << v << " : " << *v << endl;
    //else
    //    cout << v << endl;

    // 출력 구현부를 별도로 분리하여 함수 템플릿으로 타입을 구분하여 문제 해결 가능
    printv_imp(v, int2type<is_pointer_custom<T>::value>());
    // is_pointer_custom 반환 값에 의해(포인터: int2type<1>, 포인터 아님: int2type<0> 타입)
}

int main()
{
    int n = 3;
    printv(n);
    printv(&n);
}

 

integral_constant 예제

  • int뿐 아니라 모든 정수 계열 상수 값을 타입으로 만들 수 있게 하는 템플릿(실수는 템플릿 인자 사용X)

    • bool, char, short, int, long, long long
  • true_type, false_type

    • true/false: 참 거짓을 나타내는 값, 서로 같은 타입

    • true_type/false_type: 참 거짓을 나타내는 값, 서로 다른 타입

  • is_pointer등의 type_traits를 만들때 intergral_constant를 기반 클래스로 사용하여 간소화 및 가독성을 높일 수 있음
    • T가 포인터가 아니라면, value = false, 기반 클래스는 false_type
    • T가 포인터라면, value = true, 기반 클래스는 true_type
#include <iostream>
using namespace std;

template<typename T, T N> 
struct integral_constant
{
    static constexpr T value = N;
};

// int 타입 0, 1 서로 다른 타입
integral_constant<int, 0> t0;
integral_constant<int, 1> t1;

// short 타입, 0, 1 서로 다른 타입
integral_constant<short, 0> s0;
integral_constant<short, 1> s1;

// bool 타입, true, false 서로 다른 타입
integral_constant<bool, true> tb1;
integral_constant<bool, false> tb0;

// bool 타입은 활용 빈도가 높으므로 true_type, false_type 별칭 만들어서 사용
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

template<typename T>
struct is_pointer : false_type
{
    // false_type 상속으로 아래 코드 생략
    //static constexpr bool value = false;
};

template<typename T>
struct is_pointer<T*> : true_type
{
    // true_type 상속으로 아래 코드 생략
    //static constexpr bool value = true;
};

 

C++11 type_traits 활용하여 int2type 예제 간소화

  • C++11 <type_traits>헤더 포함

  • int2type<0>, int2type<1> -> integral_constant<0>, integral_constant<1>

  • integral_constant<0>, integral_constant<1> -> false_type, true_type

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

// 컴파일 타임 상수 값 구분용 함수 템플릿
template<typename T>
void printv_imp(T v, true_type)
{
    cout << v << " : " << *v << endl;
}

// 컴파일 타임 상수 값 구분용 함수 템플릿
template<typename T>
void printv_imp(T v, false_type)
{
    cout << v << endl;
}

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template<typename T> void printv(T v)
{
    printv_imp(v, is_pointer<T>());
}

int main()
{
    int n = 3;
    printv(n);
    printv(&n);
}

 

C++17 if constexpr를 사용하여 컴파일 타임에 분기처리 가능

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

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template<typename T> void printv(T v)
{
    if constexpr(is_pointer<T>::value)
        cout << v << " : " << *v << endl;
    else
        cout << v << endl;
}

int main()
{
    int n = 3;
    printv(n);
    printv(&n);
}
반응형

반응형

is_array 예제

  • 간단히 템플릿 파라미터 T가 배열 타입 여부 확인 도구

  • 메인 템플릿(Main template)에서 false 반환( value = false )

  • 배열 타입 부분 특수화(Partial specialization)에서 true 반환( value = true )

  • 타입을 정확히 알아야 함

    • int x[3]; 에서 x는 변수 이름, 변수 이름을 제외한 나머지 요소(int[3])이 타입임

  • unknown size array type(T[])에 대해서도 부분 특수화가 필요함

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

template<typename T> struct is_array_custom
{
    static constexpr bool value = false;
};

// 크기를 알 수 있는 배열의 부분 특수화
template<typename T, size_t N>
struct is_array_custom<T[N]>
{
    static constexpr bool value = true;
};

// 크기를 알 수 없는 배열의 부분 특수화
template<typename T, size_t N>
struct is_array_custom<T[N]>
{
    static constexpr bool value = true;
};

template<typename T> void foo(T& a)
{
    // 크기를 알 수 있는 배열 확인
    if (is_array_custom<T>::value)
        cout << "array" << endl;
    else
        cout << "not array" << endl;
      
    // 크기를 알 수 없는 배열을 사용하는 패턴도 존재함
    //if (is_array_custom<int[]>::value)
}

int main()
{
    int x[3] = { 1, 2, 3 };
    foo(x);
}

 

is_array 배열 크기 구하기

  • 부분 특수화로 배열의 크기도 구할 수 있음

    • c++11 extent<T, 0>::value 존재

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

template<typename T> struct is_array_custom
{
    static constexpr bool value = false;
    static constexpr size_t size = -1;
};

//사이즈를 알 수 있는 배열에 대한 부분 특수화에서 N이 배열의 크기
template<typename T, size_t N>
struct is_array_custom<T[N]>
{
    static constexpr bool value = true;
    static constexpr size_t size = N;
};

template<typename T> void foo(T& a)
{
    if (is_array_custom<T>::value)
        cout << "size of array : " << is_array_custom<T>::size << endl;
}

int main()
{
    int x[3] = { 1, 2, 3 };
    foo(x);
}
반응형

+ Recent posts