STL 캐릭터 특성의 요점은 무엇입니까?


84

SGI STL 참조 사본에 캐릭터 특성에 대한 페이지가 있지만 이것이 어떻게 사용되는지 볼 수 없습니다. string.h 함수를 대체합니까? 에 의해 사용되지 않는 것 같습니다 std::string. 예를 들어의 length()메서드 std::string는 Character Traits length()메서드를 사용하지 않습니다 . 캐릭터 특성이 존재하고 실제로 사용되는 이유는 무엇입니까?

답변:


172

문자 특성은 스트림 / 문자열 클래스 가 저장 되는 문자 의 논리와 해당 문자에 대해 수행해야하는 조작 의 논리 를 분리 할 수 ​​있도록하므로 스트림 및 문자열 라이브러리의 매우 중요한 구성 요소입니다 .

우선 기본 문자 특성 클래스 인는 char_traits<T>C ++ 표준에서 광범위하게 사용됩니다. 예를 들어라는 클래스가 없습니다 std::string. 오히려 std::basic_string다음과 같은 클래스 템플릿 이 있습니다.

template <typename charT, typename traits = char_traits<charT> >
    class basic_string;

그런 다음 다음과 std::string같이 정의됩니다.

typedef basic_string<char> string;

마찬가지로 표준 스트림은 다음과 같이 정의됩니다.

template <typename charT, typename traits = char_traits<charT> >
    class basic_istream;

typedef basic_istream<char> istream;

그렇다면 이러한 클래스가있는 그대로 구조화 된 이유는 무엇입니까? 왜 이상한 특성 클래스를 템플릿 인수로 사용해야합니까?

그 이유는 어떤 경우에는와 똑같은 문자열을 원할 수 std::string있지만 약간 다른 속성 이 있기 때문입니다 . 이에 대한 전형적인 예는 대소 문자를 무시하는 방식으로 문자열을 저장하려는 경우입니다. 예를 들어, 다음 CaseInsensitiveString과 같은 문자열을 만들 수 있습니다.

CaseInsensitiveString c1 = "HI!", c2 = "hi!";
if (c1 == c2) {  // Always true
    cout << "Strings are equal." << endl;
}

즉, 대소 문자 구분 만 다른 두 개의 문자열이 동일하게 비교되는 문자열을 가질 수 있습니다.

이제 표준 라이브러리 작성자가 특성을 사용하지 않고 문자열을 설계했다고 가정합니다. 이것은 내 상황에서 완전히 쓸모없는 엄청나게 강력한 문자열 클래스를 표준 라이브러리에 가지고 있음을 의미합니다. 비교는 항상 내가 원하는 방식에 대해 작동하기 때문에이 문자열 클래스에 대해 많은 코드를 재사용 할 수 없습니다. 그러나 트레이 트를 사용하면 실제로 std::string대소 문자를 구분하지 않는 문자열을 얻기 위해 구동하는 코드를 재사용 할 수 있습니다.

C ++ ISO 표준의 복사본을 가져 와서 문자열의 비교 연산자가 작동하는 방식에 대한 정의를 살펴보면 compare함수 측면에서 모두 정의되어 있음을 알 수 있습니다. 이 함수는 다음을 호출하여 정의됩니다.

traits::compare(this->data(), str.data(), rlen)

str비교할 문자열은 어디에 rlen있고 두 문자열 길이 중 더 작은 문자열입니다. 이것은의 정의가 템플릿 매개 변수로 지정된 특성 유형에 의해 내 보낸 함수 를 compare직접 사용 한다는 것을 의미하기 때문에 실제로 매우 흥미 롭습니다 compare! 결과적으로 새로운 특성 클래스를 정의한 다음 compare대소 문자를 구분하지 않고 문자를 비교하도록 정의 하면와 같이 동작 std::string하지만 대소 문자를 구분하지 않는 처리 하는 문자열 클래스를 만들 수 있습니다 !

여기에 예가 있습니다. std::char_traits<char>작성하지 않은 모든 함수에 대한 기본 동작을 얻기 위해 상속합니다 .

class CaseInsensitiveTraits: public std::char_traits<char> {
public:
    static bool lt (char one, char two) {
        return std::tolower(one) < std::tolower(two);
    }

    static bool eq (char one, char two) {
        return std::tolower(one) == std::tolower(two);
    }

    static int compare (const char* one, const char* two, size_t length) {
        for (size_t i = 0; i < length; ++i) {
            if (lt(one[i], two[i])) return -1;
            if (lt(two[i], one[i])) return +1;
        }
        return 0;
    }
};

( 동등 및보다 작음의 문자를 각각 비교 한 다음 이 함수의 관점에서 정의하는 eqlt여기도 정의 compare했습니다.)

이제이 특성 클래스가 있으므로 CaseInsensitiveString간단하게 다음과 같이 정의 할 수 있습니다.

typedef std::basic_string<char, CaseInsensitiveTraits> CaseInsensitiveString;

그리고 짜잔! 이제 모든 것을 대소 문자를 구분하지 않는 문자열이 생겼습니다!

물론이 외에도 특성을 사용하는 다른 이유가 있습니다. 예를 들어 고정 크기의 기본 문자 유형을 사용하는 문자열을 정의하려는 경우 char_traits해당 유형을 전문화 한 다음 해당 유형에서 문자열을 만들 수 있습니다. 예를 들어 Windows API에는 TCHAR전처리 중에 설정 한 매크로에 따라 좁거나 넓은 문자 유형 이 있습니다. 그런 다음 다음과 같이 TCHAR작성 하여 s에서 문자열을 만들 수 있습니다.

typedef basic_string<TCHAR> tstring;

이제 TCHARs 문자열이 있습니다.

이 모든 예제에서 해당 유형에 대한 문자열을 가져 오기 위해 일부 특성 클래스 (또는 이미 존재하는 것을 사용)를 일부 템플릿 유형에 대한 매개 변수로 정의했음을 주목하십시오. 이것의 요점은 basic_string저자가 특성을 사용하는 방법을 지정하기 만하면 기본 문자열 유형의 일부가 아닌 약간의 뉘앙스 또는 특이한 문자열을 얻기 위해 기본이 아닌 특성을 사용하도록 마술처럼 만들 수 있다는 것입니다.

도움이 되었기를 바랍니다!

편집 : @phooji가 지적 했듯이이 특성 개념은 STL에서만 사용되는 것이 아니며 C ++에만 국한되지 않습니다. 완전히 뻔뻔한 자기 프로모션으로, 얼마 전 특성을 사용하여 모든 유형의 문자열을 저장하고 클라이언트가 저장하기 원하는 비교 유형을 사용 하는 삼항 검색 트리 ( 여기에 설명 된 기수 트리 유형)의 구현을 작성 했습니다 . 이것이 실제로 사용되는 예를보고 싶다면 흥미로운 읽을 수 있습니다.

편집 : std::string사용하지 않는 귀하의 주장에 대한 응답으로 traits::length몇 군데에서 수행되는 것으로 나타났습니다. 당신이 만들 때 가장 두드러진 std::stringchar*C 스타일의 문자열을 문자열의 새 길이를 호출하여 파생 된 traits::length해당 문자열에. 그 보인다 traits::length반면, C ++에서 문자열의 "최소 공통 분모"문자가의 C 스타일의 시퀀스에 대처하기 위해 주로 사용되는 std::string임의의 내용의 문자열과 함께 작업하는 데 사용됩니다.


14
가되지 않도록, 부스트 라이브러리의 많은 개념과 유형의 특성 클래스를 사용 : 당신은 아마 또한 관련 사용자 이름 : 완료를 정의를 가지고있는 것처럼 보인다 단지 표준 라이브러리. 또한 유사한 기술이 템플릿을 사용하지 않고 다른 언어로 사용됩니다 . 난해한 예를 참조하십시오 : ocaml.janestreet.com/?q=node/11 .
phooji 2011 년

2
좋은 구조 (Ternary Search Tree), 그러나 Tries는 다양한 방법으로 "압축"될 수 있음을 지적합니다. 1 / 단일 문자가 아닌 자식을 가리키는 문자 범위 사용 (게인은 분명함), 2 / 경로 압축 (Patricia Trees) 및 분기 끝에있는 3 / 버킷 (즉, K 미만인 경우 정렬 된 문자열 배열 사용). 이들을 결합하면 (1과 3을 결합했습니다) 속도 성능에 일정한 요인 이상으로 영향을주지 않으면 서 메모리 소비를 대폭 줄입니다 (실제로 버킷은 점프 수를 감소시킵니다).
Matthieu M.

2
@ dan04 : 함수를 사용하기 위해 표준 클래스 / 알고리즘을 얻으십시오.
Xeo

2
그래서 ... 간단히 말해서, 트레이 트는 기본 _string 클래스가 실제로 어떤 문자인지에 관계없이 다양한 유형의 문자를 조작하는 데 사용하는 일종의 인터페이스입니다.
Virus721

1
@ Virus721 특성은 주어진 클래스에 "플러그인"된 구현이 아닙니다. 클래스가 트레이 트에서받는 것은 인터페이스가 아니라 구현 인 IMHO입니다. 물론 특성에는 인터페이스가 있습니다.
dom_beau
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.