C++traits 기술 깊이 분석

10676 단어 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。(추출 기 는 가장 특별한 버 전과 일치 합 니 다)이렇게 하면 네 이 티 브 포인터 가 들 어 갈 때 먼저가 있 는 편 특 화 버 전 과 일치 합 니 다.이렇게 valuetype 은 T 입 니 다.미리 설명 하지 않 은 I::value 가 아 닙 니 다.type。이렇게 값 을 되 돌려 주면 type:name iterator 를 사용 할 수 있 습 니 다.traits::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 기술 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 하 세 요!

좋은 웹페이지 즐겨찾기