2012-09-01 2 views
1

나는 C++에서 완전히 무엇이든지 매핑 할 수있는 매핑을 정의하고 싶습니다.C++에서 any-to-any 매핑을 정의하려면 어떻게해야합니까?

std :: map을 시도했지만 K와 V가 원시 또는 객체 (키)를 다른 프리미티브 또는 객체 (값)에 매핑 할 수 있도록 충분히 일반화해야하는 이유는 무엇입니까?

또는 사용할 수있는 또 다른 메커니즘이 있습니까?

EDIT : 명확한 설명을 위해, 모든 클래스가 파생 된 기본 클래스에서 임의의 데이터를 클래스에 첨부 할 수 있도록 관계를 정의하려고합니다. 가장 간단한 방법은 위의 키가 문자열 인 이름 - 값 쌍이 될 수 있습니다. 좀 더 일반적인 일을하는지 궁금 해서요?

답변

6

불가능합니다. 그러한 매핑은 아무런 의미가없는 키나 값의 동작에 의존 할 수 없기 때문에 무가치합니다. "anything"에 걸쳐 의미있는 이진 관계 나 해시 함수를 설계하는 것은 불가능합니다. 타입이기 때문에 가능한 영역조차 없다.

편집 : 어떤 유형의 std::unordered_map을 보유하게되는 boost::any 또는 실제로 boost::any을 방해하는 것이 없습니다.

그러나 디자인이 매우 의심스러운 것으로 보입니다.기본적으로 컴파일러는 명백한 이점을 전혀 얻지 못하고 있습니다. 왜 모든 수업을 공통 기초에서 파생 시켰습니까? 왜 지구상에 임의의 데이터를 첨부하고 싶습니까? 클래스에 데이터를 넣는 일반적인 방법은 클래스에 넣으십시오. C++을 해석 된 언어로 강요하여 모든 안전성과 성능 및 온전함을 날려 버리지는 마십시오.

+0

한편, 좋은 해결책은'std :: unordered_map'입니다. 나의 이전 +1에 대한 더 많은 이유! – Linuxios

+0

좋은 점 @DeadMG. 이것은 제한된 기능 (많은 파생 클래스가 아니기 때문에)에서 공통 클래스에서 파생되지만,이 클래스의 클라이언트가 보충 데이터로 첨부해야하는 것을 미리 알지 못합니다. –

+1

@AndrewS .: 고객이 기능을 필요로하는 경우에도 데이터를 연결하는 것에 대해 걱정할 필요가 있습니다. 그들은'std :: unordered_map <파생 된 *, ThatDataWhichNeed>'할 수 있습니다. – Puppy

-1

K 및 V를 특수 개체로 만들어야합니다.

개체는 개체 유형을 포함해야합니다.

위의 개체는 무엇이든 가리킬 수 있습니다. 그러나, 그것은 또한 그것이 어떤 유형인지, 따라서 유형 문자열을 말할 무언가를 필요로합니다.

그런 다음 입력 내용을 읽음으로써 필요한 유형으로 포인터를 다시 캐스팅 할 수 있어야합니다.

예 : 당신이 뭔가를 할 경우

if (type == "int") cout << (int*)(myobject.pointer) << endl; 

어쨌든, 당신은 거의 당신이 개체에 대해 수행 할 모든 작업을 위해, 당신은 그것의 유형을 확인해야하므로, 느슨하게 입력 인터프리터를 구축하기 시작했다 (당신 여부 값을 stdout에 추가, 연결 또는 인쇄하고 있음).


클래스 개체를 사용하고 상속을 사용하여 필요한 모든 데이터를 저장하는 것이 좋습니다.

class Object { 
    public virtual string to_string() { 
    return ""; 
    } 
}; 

그럼 당신은 정수 저장하려면 : 당신은 모든 개체를 지원하려는 모든 기능의 인터페이스를 정의 할 수 있습니다

class Integer : public Object { 
    int i; 
    public string to_string() { 
    char str[50]; 
    sprintf(str,"%d",i); 
    return string(str); 
    } 
    public Integer operator=(int a) { 
    i=a; 
    return this; 
    } 
}; 

이 방법을. 기본 개체 클래스를 만드는 것은 가상 기능을 가지고

주 즉, 당신이 말한다면 :

Integer a; 
a=5; 
Object object = (Object)a; 
cout << object.to_string << endl; // prints "5" 

소위 함수가 객체의 실제 (true)가 타입에 의해 정의한다는 것을.

1

가능합니다 -이 시점에서 나는 @DeadMG와 동의하지 않습니다.

그것은 가치가 - 내 말은 내가 대답의 개념을 이해하지 않는다 그러나이 시점 전체 계약,

, 대답 대신 "이이 방법으로 수행 할 수 있습니다"는하지 않는다 ",하지만 내 조언하지 마라. " 나는 "선생님"인 척하지 않는다. 나는 단지 대답하고있다.

값은 - boost :: any와 같이 사용한다.

키의 경우 - std :: map은 키의 순서를 정의하기 때문에 더 복잡합니다. 그래서 일반적인 키 살전 규칙을 따라야합니다 :

  1. 을 실제 키 유형이 동일한 경우 - 당신이 소속 카테고리의 순서와 같은 종류의 (사이의 순서를 정의해야합니다 - 실제 키가 동일하지 않으면 실제 키에서
  2. 을 순서를 사용 :: 이름())
  3. 일반 키를 복사해야 작도

유형의 삭제를 사용하여 키 (내 제안) 보자 :

template <typename T> 
struct GenKeyTypeOrder; 


class GenKeyImplInt { 
public: 
    // true if before other Key in other 
    virtual bool before(const GenKeyImplInt&) const = 0; 
    // type value 
    virtual int typeOrder() const = 0; 

    virtual GenKeyImplInt* clone() const = 0; 
    virtual ~GenKeyImplInt() {} 
}; 

template <typename RealKey> 
class GenKeyImpl : public GenKeyImplInt { 
public: 
    GenKeyImpl(RealKey realKey) : realKey(realKey) {} 
    // true if before other Key in other 
    virtual bool before(const GenKeyImplInt& r) const 
    { 
     const GenKeyImpl* rp = dynamic_cast<const GenKeyImpl*>(&r); 
     if (rp) return realKey < rp->realKey; 
     return typeOrder() < r.typeOrder(); 
    } 
    // type value 
    virtual int typeOrder() const { return GenKeyTypeOrder<RealKey>::VALUE; } 

    virtual GenKeyImpl* clone() const { return new GenKeyImpl(*this); } 
private: 
    RealKey realKey; 
}; 

class GenKey { 
public: 
    // true if before other Key in other 
    friend bool operator < (const GenKey& l, const GenKey& r) 
    { 
     return l.impl->before(*r.impl); 
    } 
    template <typename T> 
    GenKey(T t) : impl(new GenKeyImpl<T>(t)) {} 
    GenKey(const GenKey& oth) : impl(oth.impl->clone()) {} 
    ~GenKey() { delete impl; } 
private: 
    GenKey& operator = (const GenKey& oth); // not defined 
    GenKeyImplInt* impl; 
}; 


// define for every type you want be used as generic key 
template <> 
struct GenKeyTypeOrder<int> { enum { VALUE = 0 }; }; 
template <> 
struct GenKeyTypeOrder<std::string> { enum { VALUE = 1 }; }; 

전체 예제 : ideone 참고 사항 : article

+0

아무 것도 매핑하지 않았습니다. 당신은 *와 *가'operator < '를 지원하도록 명시 적으로 등록 된 타입만을 매핑했습니다. – Puppy

+0

@DeadMG이 문제를 해결하기위한 첫 시도였습니다. 제네릭 형식 순서를 쉽게 상상할 수 있습니다. 따라서 형식을 구체적으로 등록 할 필요가 없습니다. 예 : typeid (T) .name()을 사용합니다. 두 번째 문제 : 일부 형식의 특정 순서를 정의하여 std :: less <>를 기본값으로 유지할 수 있습니다. 확실히 다른 솔루션은 정렬되지 않은/해시 맵일 것입니다 - 예를 들어, name (typeid) 및 객체의 문자열 표현과 같은 최종 해시 함수 'operator =='와 같은 해시 함수를 고려하십시오. BTW, '연산자 <'를 정의 할 수없는 객체 클래스를 알고 계십니까? – PiotrNycz

관련 문제