C++traits 기술 깊이 분석
traits 는 특성 추출 기술 이 라 고도 불 린 다.쉽게 말 하면'들 어 오 는 대상'에 대응 하 는 반환 유형 을 추출 하여 같은 인터페이스 에 대응 하 는 기능 을 실현 하 는 것 이다.STL 의 알고리즘 과 용 기 는 분리 되 어 있 기 때문에 둘 은 교체 기 를 통 해 연결된다.계산법 의 실현 은 자신 이 무엇 을 들 어 왔 는 지 모른다.추출 기 는 인터페이스 와 실현 사이 에 봉인 을 해서 세부 사항 을 숨 기 고 적당 한 방법 을 호출 하 는 데 도움 을 주 는 것 과 같다.이것 은 약간의 기교(예 를 들 어 편 특 화)가 필요 하 다.마지막 으로 작은 예 를 들 어 특성 추출 을 잘 이해 할 수 있 을 것 이다.
다음은 대부분'STL 소스 코드 분석'에서 유래 한 것 으로 원 서 를 보면 더 자세 한 내용 을 알 수 있다.
Traits 프로 그래 밍 기법
조금씩 문 제 를 던 지고 조금씩 깊이 들 어가 자.
1.우선 알고리즘 에서 교체 기 를 사용 할 때 해당 유형(교체 기 가 가리 키 는 물건 의 유형)을 사용 할 수 있 습 니 다.가설 알고리즘 에서 변 수 를 설명 할 필요 가 있 는데'교체 기 가 가리 키 는 대상 의 유형'을 유형 으로 하면 어떻게 해 야 합 니까?
해결 방법 은 function template 의 매개 변수 유도 체 제 를 이용 하 는 것 이다.
template <class I, class T>
void func_impl(I iter, T t) {
T tmp; //
// ...
}
template <class I>
inline
void func(I iter) {
func_impl(iter, *iter); // iter iter ,class
}
int main() {
int i;
func(&i);
}
패 키 징 의 뜻 을 알 수 있 습 니 다.impl 의 패 키 징 이 없 으 면 매번 교체 기 가 대상 형 태 를 가리 키 는 것 을 명시 적 으로 설명 해 야 tmp 변 수 를 새로 만 들 수 있 습 니 다.포장 을 한 겹 더 하면 훨씬 산뜻 해 보인다.교체 기 해당 형 태 는'교체 기 가 가리 키 는 대상 의 형 별'만 있 는 것 이 아니다.경험 에 따 르 면 가장 자주 사용 하 는 해당 형 태 는 다섯 가지 가 있 지만 그 어떠한 상황 에서 도 상기 template 매개 변수 유도 체 제 를 이용 하여 얻 을 수 있 는 것 은 아니다.
함수 의'template 매개 변수 유도 메커니즘'은 매개 변수 일 뿐 함수 의 반환 값 유형 을 유도 할 수 없습니다.만일 유도 함수 의 전송 값 이 필요 하 다 면 어 쩔 수 없다.
2.내장 형 태 를 밝 히 는 것 은 좋 은 생각 인 것 같 습 니 다.그러면 우 리 는 직접 얻 을 수 있 습 니 다.
template <class T>
struct MyIter {
typedef T value_type; //
// ...
};
template <class I>
typename I::value_type
func(I ite) {
return *ite;
}
// ...
MyIter<int> ite(new int(8));
cout << func(ite);
보기 에는 좋 지만 모든 교체 기 가 class type 인 것 은 아 닙 니 다.원생 지침 이 안 됩 니 다!class type 이 아니라면 내장 형 태 를 정의 할 수 없습니다.이 럴 때 는 편 특 화가 필요 하 다.
3.편 특 화 는 특 화 를 바탕 으로 약간의 제한 을 더 하 는 것 이지 만 특 화 된 template 이다.
template <class I>
struct iterator_traits {
typedef typename I::value_type value_type;
};
template <class I>
struct iterator_traits<T*> {
typedef T value_type;
};
template <class I>12 typename iterator_traits<I>::value_type
func(I ite) {
return *ite;
}
func 가 I 를 호출 할 때 먼저 I 를 추출 기 에 전달 한 다음 추출 기 가 가장 적합 한 value 와 일치 합 니 다.type。(추출 기 는 가장 특별한 버 전과 일치 합 니 다)이렇게 하면 네 이 티 브 포인터 가 들 어 갈 때 먼저아래 에 의 사진 을 동봉 합 니 다.
traits 에 게 더 많은 것 을 시 키 세 요.
교체 기 는 흔히 볼 수 있 는 다섯 가지 유형 이 있 습 니 다:valuetype, difference_type, reference_type, pointer_type 은 모두 traits 와 해당 하 는 편 특 화 에서 추출 하기 쉽다.하지만,iteratorcategory 는 보통 5 개 로 해당 형 태 는 비교적 큰 규모 의 코드 작성 공 사 를 일 으 킬 수 있다.
예 를 들 어 우 리 는 func 를 실현 했다.II, func_BI, func_RAI 는 각각 교체 기 유형 을 대표 하 는 Input Iterator,Bidirectional Iterator,Random Access Iterator 의 대응 실현 이다.
현재,고객 측 이 func()를 호출 할 때,우 리 는 판단 을 해 야 할 수도 있 습 니 다.
template<class Iterator>
void func(Iterator& i) {
if (is_random_access_iterator(i))
func_RAI(i);
if (is_bidirectional_iterator(i))
func_BI(i);
else
func_II(i);
}
그러나 이렇게 실행 시기 에 야 어떤 버 전 을 사용 할 지 결정 하고 프로그램의 효율 에 영향 을 줄 수 있다.컴 파일 기간 에 정확 한 버 전 을 선택 하 는 것 이 좋 습 니 다.이 함수 메커니즘 을 다시 불 러 오 면 이 목 표를 달성 할 수 있다.
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
// ...
// , input_iterator_tag
// forward_iterator_tag, ,
일부 열 tag 를 설명 한 후에 우 리 는 func 함수:func(tag)를 다시 불 러 올 수 있 습 니 다.여기까지 각 유형의 구체 적 인 적재량 실현 은 이미 다 썼 지만 통 일 된 인터페이스 가 필요 합 니 다.이때 traits 가 등장 할 수 있 습 니 다.
template<class Iterator>
inline void func(Iterator& i)
{
typedef typename Iterator_traits<Iterator>::iterator_category category;
__func(i, category()); //
}
단순 인 스 턴 스 코드그 러 니까 traits 는 한편,서로 다른 입력 유형 에 직면 할 때 적당 한 반환 형 태 를 찾 을 수 있 습 니 다.다른 한편,유형 별 대응 이 서로 다른 실현 함수 가 있 을 때 추출 형 별 후 분류 하 는 역할 을 할 수 있다.
먼저 우리 가 func 함수 가 있다 고 가정 하면 사용자 정의 클래스 나 원본 지침 을 매개 변수 로 받 아들 일 수 있 고 어떤 tag 를 사용 하 는 지 자동 으로 출력 할 수 있 습 니 다.
먼저 traits(자체 또는 편 특 화 버 전 으로 구현)에 따라 u 의 반환 형 태 를 추출 한 다음 에 해당 하 는 구조 함수 return 을 호출 합 니 다.type(),각 리 셋 버 전 으로func 의 과부하 표 지 는 서로 다른 실제 함 수 를 구분 합 니 다.
우선 인터페이스 코드 의 작성 을 살 펴 보 겠 습 니 다.
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type //
func(unknown_class u) {
typedef typename unknown_class_traits<unknown_class>::return_type return_type;
return __func(u, return_type()); // tag
}
그리고 설정 을 실현 하 는 tag,앞에서 말 한 II,RAI 등 을 모방 하 는 데 쓰 인 다.
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
return_type(unknown_class) {
typedef typename unknown_class_traits<unknown_class>::return_type RT;
return RT();
}
이게 있 으 면 저희 가 테스트 를 할 수 있어 요.
struct A {};
struct B : A{};
그 다음은 traits 가 성대하게 등장 해 두 가지 특 화 버 전이 있다.
/* */
template <class unknown_class>
struct unknown_class_traits {
typedef typename unknown_class::return_type return_type;
};
/* ―― */
template <class T>
struct unknown_class_traits<T*> {
typedef T return_type;
};
/* ―― */
template <class T>
struct unknown_class_traits<const T*> {
typedef const T return_type;
};
갑자기 잊 어 버 렸 어 unknownclass 의 구조,사용자 정의 클래스,type:def 가 필요 합 니 다.
template <class AorB>
struct unknown_class {
typedef AorB return_type;
};
마지막 으로 func 각 리 셋 버 전 입 니 다.
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, A) {
cout << "use A flag" << endl;
return A();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, B) {
cout << "use B flag" << endl;
return B();
}
template <class unknown_class, class T>
T
__func(unknown_class, T) {
cout << "use origin ptr" << endl;
return T();
}
이게 있 으 면 저희 가 테스트 를 할 수 있어 요.
int main() {
unknown_class<B> b;
unknown_class<A> a;
//unknown_class<int> i;
int value = 1;
int *p = &value;
A v1 = func(a);
B v2 = func(b);
int v3 = func(p);
char ch = getchar();
}
사용자 정의 클래스 로 같은 인터페이스 에 들 어 오 면 해당 하 는 함 수 를 자동 으로 사용 하고 값 을 되 돌려 주 는 것 도 적당 하 다 는 것 을 알 수 있다.원본 포인터 에 도 적용,완벽!붙다
다음은 전체 코드 입 니 다.
#include <iostream>
using namespace std;
/* tag*/
struct A {};
struct B : A{}; // , A,
// B ,
/* */
template <class AorB>
struct unknown_class {
typedef AorB return_type;
};
/* */
template <class unknown_class>
struct unknown_class_traits {
typedef typename unknown_class::return_type return_type;
};
/* ―― */
template <class T>
struct unknown_class_traits<T*> {
typedef T return_type;
};
/* ―― */
template <class T>
struct unknown_class_traits<const T*> {
typedef const T return_type;
};
/* */
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
return_type(unknown_class) {
typedef typename unknown_class_traits<unknown_class>::return_type RT;
return RT();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, A) {
cout << "use A flag" << endl;
return A();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
__func(unknown_class, B) {
cout << "use B flag" << endl;
return B();
}
template <class unknown_class, class T>
T
__func(unknown_class, T) {
cout << "use origin ptr" << endl;
return T();
}
template <class unknown_class>
inline typename unknown_class_traits<unknown_class>::return_type
func(unknown_class u) {
typedef typename unknown_class_traits<unknown_class>::return_type return_type;
return __func(u, return_type());
}
int main() {
unknown_class<B> b;
unknown_class<A> a;
//unknown_class<int> i;
int value = 1;
int *p = &value;
A v1 = func(a);
B v2 = func(b);
int v3 = func(p);
char ch = getchar();
}
종결 어특성 추출 에 많은 시간 이 걸 렸 지만 프로그램 이 뛰 어 나 오 는 순간 즐 거 웠 다.
우선 후 제 선생님 께 감 사 드 려 야 합 니 다.선생님 의 책 을 이렇게 분명하게 말씀 해 주 셔 서 저 는 어 리 석 게 읽 었 습 니 다.
이 걸 보고 그림 을 볼 수 있 는 푸 리 엽 이 바 뀌 었 어 요.아하 하~
이상 은 C++traits 기술 에 대한 상세 한 내용 입 니 다.C+traits 기술 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Visual Studio에서 파일 폴더 구분 (포함 경로 설정)Visual Studio에서 c, cpp, h, hpp 파일을 폴더로 나누고 싶었습니까? 어쩌면 대부분의 사람들이 있다고 생각합니다. 처음에 파일이 만들어지는 장소는 프로젝트 파일 등과 같은 장소에 있기 때문에 파일...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.