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.