함수 찾는 순서
- 1순위 정확한 매칭(exactly matching)
- 2순위 템플릿(template)
- 3순위 가변 인자(variable argument)
#include <iostream>
using namespace std;
template<typename T>
// 2순위 템플릿(template)
void foo(T t) { cout << "T" << endl; }
// 1순위 정확한 매칭(exactly matching)
void foo(int n) { cout << "int" << endl; }
// 3순위 가변 인자(variable argument)
void foo(...) { cout << "..." << endl; }
int main()
{
    foo(3);
}
SFINAE
- 
Substitution Failure Is Not An Error 
- 
함수 템플릿을 사용시 T의 타입이 결정되고 함수를 생성(Instantiation)하려고 할때 리턴 타입이나 함수 인자등에서 치환에 실패하면 컴파일 에러가 아니라, 함수 후보군에서 제외함 
- 
동일한 이름의 다른 함수가 있다면 다른 함수를 사용하게 됨 
#include <iostream>
using namespace std;
template<typename T>
typename T::type foo(T t) 
{ 
    cout << "T" << endl; return 0; 
}
void foo(...) 
{ 
    cout << "..." << endl; 
}
int main()
{
    // 가변인자 함수보다 템플릿 함수가 우선순위가 높아서 먼저 참조하게 되지만 리턴 타입에서 
    // int 타입::type은 존재하지 않으므로 만족할 수 없으므로 후보군에서 제외되고 가변인자 버전의 함수가 사용됨
    foo(3); // T
}
enable_if
- 
c++표준에서 지원하는 도구 
- 
1번째 인자가 true일 경우만 type이 정의됨 - 
enable_if<true, int>::type -> int 
- 
enable_if<true>::type -> void 
- 
enable_if<false, int>::type -> error 
- 
enable_if<false>::type -> error 
 
- 
#include <iostream>
using namespace std;
template<bool b, typename T = void> struct enable_if
{
};
template<typename T> struct enable_if<true, T>
{
    typedef T type;
};
int main()
{
    //enable_if<true, int>::type t0; // 타입이 int로 결정
    //enable_if<true>::type t1; // 타입이 void로 결정
    //enable_if<false, int>::type t2; // 타입이 없어서 error
}
enable_if 예제
- 
정수일때만 동작하는 함수를 만들고 싶을때 - 
static_assert - 
처리하게 되면 조건을 만족하지 않을 경우 컴파일 에러 
 
- 
- 
enable_if - 
SFINAE 특성을 활용한 방법 
- 
조건을 만족하지 않으면 함수를 생성하지 않고 다른 후보가 있다면 사용함 
- 
확장성 유리 
 
- 
 
- 
#include <iostream>
using namespace std;
// 정수일때만 함수 코드를 생성하고 싶음
template<typename T>
typename enable_if<is_integral<T>::value, int>::type
foo(T a)
{
    cout << "T" << endl;
    return 0;
}
void foo(...)
{
    cout << "not integer" << endl;
}
int main()
{
    foo(2.3);
}
enable_if 위치
- 
함수 리턴 타입 
- 
함수 인자 타입 -> 생성자에서 주로 사용 
- 
템플릿 인자 -> 함수 자체의 모양이 단순해 보이는 장점 있음 
#include <iostream>
using namespace std;
// 함수 리턴 타입 위치
template<typename T>
typename enable_if<is_integral<T>::value, int>::type
foo(T a)
{
    cout << "T" << endl;
    return 0;
}
// 함수 인자 타입 위치(리턴 타입이 없는 생성자에서 주로 사용)
template<typename T>
void foo(T a, 
    typename enable_if<
    is_integral<T>::value>::type* = nullptr)
{
    cout << "T" << endl;
}
// 템플릿 인자(함수 자체의 원형이 최대한 유지됨으로 간결해 보이는 장점)
template<typename T, 
    typename enable_if<
    is_integral<T>::value>::type* = nullptr>
void foo(T a)
{
    cout << "T" << endl;
}
// 모두 만족하지 않을때 호출
void foo(...)
{
    cout << "not integer" << endl;
}
int main()
{
    foo(2); // 템플릿 함수 호출(현재 예제코드는 3개의 템플릿이 만족함으로 에러 발생함)
    foo(2.3); // foo(...) 호출
}
타입의 종류에 따라 다르게 동작하는 함수 생성 방법
- type_traits(is_pointer) + if constexpr // C++17에서만 가능
- type_traits + 함수 오버로딩(false_type, true_type)
- 디스패치 함수 1개 더 필요
 
- type_traits + enable_if
// C++17이상 가능 if constexpr 사용 방법
#include <iostream>
using namespace std;
template<typename T> void printv(const T& v)
{
    if constexpr(is_pointer<T>::value)
        cout << v << ":" << *v << endl;
    else
        cout << v << endl;
}
int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}// type_traits + 함수 오버로딩(false_type, true_type)
#include <iostream>
using namespace std;
template<typename T>
void printv_imp(const T& v, true_type)
{
    cout << v << ":" << *v << endl;
}
template<typename T>
void printv_imp(const T& v, false_type)
{
    cout << v << ":" << endl;
}
template<typename T> void printv(const T& v)
{
    printv_imp(v, is_pointer<T>());
}
int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}// type_traits + enable_if 사용 방법
#include <iostream>
using namespace std;
template<typename T> 
typename enable_if<is_pointer<T>::value>::type 
printv(const T& v)
{
    cout << v << ":" << *v << endl;
}
template<typename T> 
typename enable_if<!is_pointer<T>::value>::type
printv(const T& v)
{
    cout << v << ":" << endl;
}
int main()
{
    int n = 0;
    printv(n);
    printv(&n);
}'프로그래밍 언어 > C++' 카테고리의 다른 글
| C++ 템플릿 디자인 Typelist (0) | 2021.01.10 | 
|---|---|
| C++ 템플릿 디자인 Member Detect IDioms (0) | 2021.01.10 | 
| C++ 템플릿 디자인 단위 전략(Policy-Based Design) (0) | 2021.01.09 | 
| C++ 템플릿 디자인 패턴 CRTP 활용 (0) | 2021.01.08 | 
| C++ 템플릿 디자인 패턴 CRTP(Curiously Recurring Template Pattern) 패턴 (0) | 2021.01.07 |