반응형
함수 찾는 순서
- 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 |