typedef를 언제 사용해야합니까?


14

C ++에서 typedef를 사용 해야하는지 여부와 시간에 대해 약간 혼란 스럽습니다. 나는 그것이 가독성과 선명도 사이의 균형 잡힌 행동이라고 생각합니다.

typedef가없는 코드 샘플은 다음과 같습니다.

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    static std::map<std::tuple<std::vector<int>::const_iterator,
                               std::vector<int>::const_iterator>,
                    int> lookup_table;

    std::map<std::tuple<std::vector<int>::const_iterator,
                        std::vector<int>::const_iterator>, int>::iterator lookup_it =
        lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

꽤 못생긴 IMO. 따라서 함수 내에 typedef를 추가하여 더보기 좋게 만듭니다.

int sum(std::vector<int>::const_iterator first, 
        std::vector<int>::const_iterator last)
{
    typedef std::tuple<std::vector<int>::const_iterator,
                       std::vector<int>::const_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

코드는 여전히 약간 어색하지만 대부분의 악몽 자료를 제거합니다. 그러나 여전히 int 벡터 반복자가 있지만이 변형은 다음을 제거합니다.

typedef std::vector<int>::const_iterator Input_iterator;

int sum(Input_iterator first, Input_iterator last)
{
    typedef std::tuple<Input_iterator, Input_iterator> Lookup_key;
    typedef std::map<Lookup_key, int> Lookup_table;

    static Lookup_table lookup_table;

    Lookup_table::iterator lookup_it = lookup_table.find(lookup_key);

    if (lookup_it != lookup_table.end())
        return lookup_it->second;            

    ...
}

이것은 깨끗해 보이지만 여전히 읽을 수 있습니까?

언제 typedef를 사용해야합니까? 악몽 유형이 되 자마자? 그것이 두 번 이상 발생하자마자? 어디에 두어야합니까? 함수 시그니처에 사용하거나 구현에 유지해야합니까?


1
아니 중복,하지만 약간 내 질문에 관련 programmers.stackexchange.com/questions/130679/...
— c0da

typedef Input_iterator std::vector<int>::const_iterator;거꾸로
— 당 Johansson

1
가독성과 선명도에는 차이가 있습니까?
— Neil

#define충분하지 않을 때 .
— Thomas Eding

답변:


6

마지막 예제는 읽기가 쉽지만 typedef를 정의한 위치에 따라 다릅니다. 로컬 범위 typedef는 (두 번째 예에서와 같이) 거의 항상 승리입니다.

나는 여전히 세 번째 예제를 가장 좋아하지만 이름 지정에 대해 생각하고 컨테이너의 의도를 알려주는 반복자 이름을 지정할 수 있습니다.

다른 옵션은 템플릿을 함수에서 만들어 다른 컨테이너에서도 작동하도록하는 것입니다. 라인을 따라

template <typename Input_iterator> ... sum(Input_iterator first, Input_iterator last) 

이는 또한 STL의 정신에도 있습니다.


2

typedefa를 함수와 동등한 변수 선언으로 생각하십시오 .

  • ... 동일한 유형을 재사용 할 때 반복하지 않아도됩니다 (처음 두 예제 에서처럼).
  • ... 유형의 세부 사항을 숨겨서 항상 표시되지 않을 수 있습니다.
  • ... 유형에 대한 변경 사항이 사용되는 모든 장소에 반영되도록하십시오.

개인적으로, 긴 타입의 이름을 std::vector<int>::const_iterator반복해서 읽어야한다면 글씨를 쓰게됩니다 .

세 번째 예제는 불필요하게 반복되지 않으며 읽기가 가장 쉽습니다.


1

typedef선언은 본질적으로 캡슐화와 같은 목적으로 사용됩니다. 따라서 클래스와 동일한 명명 규칙에 따라 거의 항상 헤더 파일에 가장 적합합니다.

  • 당신이 필요하다면 typedef, 특히 인수에서 사용되는 예제에서와 같이 호출자가 할 가능성이 있습니다.
  • 수업을 자신의 수업으로 교체하는 것을 포함하여 어떤 이유로 든 유형을 변경해야하는 경우 한 곳에서만 수행하면됩니다.
  • 복잡한 유형을 반복해서 작성하기 때문에 실수가 덜 발생합니다.
  • 불필요한 구현 세부 사항을 숨 깁니다.

제쳐두고, 메모 코드는 다음과 같이 더 추상화하면 훨씬 더 깨끗합니다.

if (lookup_table.exists(first, last))
    return lookup_table.get(first, last);

제안이 더 깔끔해 보일 수 있지만 조회를 두 번 수행하면 시간이 낭비됩니다.
— Derek Ledbetter

그렇습니다. 이것은 의도적 인 트레이드 오프였습니다. 그러나 스레드 안전에 대해 걱정하지 않는 경우 거의 깔끔한 단일 조회로이를 수행하는 방법이 있습니다.
— Karl Bielefeldt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.