2016-07-12 3 views
3

퍼포먼스상의 이유로 값이 서로 다른 두 요소를 가리키는 두 개의 코드가 필요합니다.
다른 요소가 이미 통과 된 경우 요소의 일정 시간 삽입/제거를 허용하기위한 것입니다.값이 서로 다른 두 개의 std :: map의 iterators입니까?

C++에서 이것을 올바르게 구현하는 가장 빠른 방법은 무엇입니까? 첫 번째 맵의 값 유형으로 iterator를 선언하기 전에 두 번째 맵의 유형이 불완전하기 때문에 명백한 접근 방식이 작동하지 않는다는 점에 유의하십시오. Variants이 내 유일한 옵션입니까 아니면 더 나은 솔루션입니까?

+0

반드시 반복기 여야합니까? 그들은 단순히 값에 대한 포인터 일 수 있습니까? –

+0

@RichardHodges : 포인터가 두 번째 문장에서 설명한 제약 조건을 충족시킬 수 있습니까? 더 많은 정보가 없으면 – Mehrdad

+0

말할 수 없습니다. value_type에 대한 void 포인터는 키를 생성하기 위해 캐스팅 될 수 있지만 .... 나는 그것이 당신이 원하는 것이 아님을 안다. 아마도 우려를 나눌 시간이 되었습니까? 저장 및 색인 생성? –

답변

2

필자는 알고있는 것처럼 (전달) 선언으로는 달성 할 수없는 방식으로 상호 재귀 적 유형을 원합니다. 그러나 C++ 유명한 CRTP 또 다른 평균 제공 :

#include <map> 

template <typename T> 
struct BidirMapHelper { 
    struct ReverseElt { 
     ReverseElt() {} 
     ReverseElt(typename T::iterator p) : v(p) {} 
     typename T::iterator v; 
    }; 
    typedef std::map<int, ReverseElt> ReverseMap; 
}; 

struct BidirMap: BidirMapHelper<BidirMap> 
{ 
    struct DirectElt { 
     DirectElt() {} 
     DirectElt(ReverseMap::iterator p) : v(p) {} 
     ReverseMap::iterator v; 
    }; 
    typedef std::map<int, DirectElt> DirectMap; 
    typedef DirectMap::iterator iterator; 
}; 

typedef BidirMap::DirectMap DirectMap; 
typedef BidirMap::ReverseMap ReverseMap; 

int main() { 
    DirectMap m1; 
    ReverseMap m2; 
    m1[0] = m2.end(); 
    m2[0] = m1.end(); 
    return 0; 
} 

이 리눅스에서 g ++ 및 그 소리 ++로 깨끗하게 컴파일을,하지만 난 그것을 표준 라이브러리의 구현 특성에 의존하지 않는 모르겠어요 인정합니다 예를 들어 SCARY 반복자가 있습니다.

+0

+1, 이것은 매우 똑똑하고 내가 원하는 해결책의 종류이지만, 나는 이것이 깔끔하게 컴파일되는 것에 놀랐다. 'BidirMapHelper '타입이'ReverseElt'에서 인스턴스화 될 때'typename BidirMap :: iterator'는 정의되지 않았습니까? 아니면 'ReverseElt'로 싸여 졌기 때문에 지연된 유형의 인스턴스화가 있습니까? – Mehrdad

+0

해당 문제는 매개 변수의 템플릿을 인스턴스화하는 동안의 가용성에 따라 달라지는 CRTP의 대부분의 용도와 다르지 않습니다. 그러나 더 많이 생각할수록, std :: map의 구현 특성에 따라 달라 지므로 설득력을 발휘할 수 있습니다 (일반적으로 디커플링은 멤버 함수 본문을 고려하여 제공됩니다.) 클래스가 더 이상 불완전하지 않은 경우에만). – AProgrammer

+0

일반적인 CRTP에서 이러한 종속 형의 사용법은 멤버 함수 내부에 있으며 여러분이 말했듯이, 사용되기 전까지 인스턴스화되지 않습니다.이 시점에서 유형이 완료됩니다. 여기는 멤버 선언에 있습니다. 그래서 그것이 왜 작동해야하는지 혼란 스럽습니다 ... – Mehrdad

1

다음은 더 간단한 솔루션입니다. 그러나 std::map의 임의 표준 호환 구현을 위해 컴파일되지는 않습니다. 그러나 gcc 4.4.7 (-std = C++ 11도 지원하지 않음)과 gcc 5.x, gcc 6.1, clang 3.x 및 icc 13.0.1 (-std = C++ 11).

#include <map> 

struct It1; 
struct It2; 

typedef std::map<int, It2> Map1; 
typedef std::map<int, It1> Map2; 

struct It2 : Map2::iterator 
{ 
    It2() {} 
    It2(Map2::iterator it) : Map2::iterator(it) {} 
}; 

struct It1 : Map1::iterator 
{ 
    It1() {} 
    It1(Map1::iterator it) : Map1::iterator(it) {} 
}; 

int main() 
{ 
    Map1 m1; 
    Map2 m2; 

    m1[0] = m2.end(); 
    m2[0] = m1.end(); 
    return 0; 
} 
+0

불완전한 타입을 템플릿으로 인스턴스화하기 때문에 GCC와 작동하지만 기술적으로 정의되지 않은 동작입니다 논의. –

+0

@JonathanWakely 여기에 정의되지 않은 동작 *이라는 용어를 사용하지 않겠습니다. 어쩌면 표준에 따르면 컴파일하는 것이 보장되지는 않지만 위험한 의미에서 UB가 아닙니다. 컴파일하면 문제없이 작동합니다. – Leon

+0

내가 말했듯이, 그것은 기술적으로 ** 정의되지 않은 동작입니다. –

관련 문제