2008-10-16 9 views
14

특정 데이터 소스에 대한 메타 데이터를 저장하는 클래스를 만드는 중입니다. 메타 데이터는 XML로 구조화 된 것과 매우 유사한 트리 구조로되어 있습니다. 메타 데이터 값은 정수, 십진 또는 문자열 값이 될 수 있습니다.C++ 변형

C++에서 이와 같은 상황에 대한 변형 데이터를 저장하는 좋은 방법이 있는지 궁금합니다. 표준 라이브러리를 사용하는 변형이 필요하므로 사용할 수있는 COM, Ole 및 SQL VARIANT 형식을 피할 수 있습니다.

나의 현재 솔루션은 다음과 같은 :

enum MetaValueType 
{ 
    MetaChar, 
    MetaString, 
    MetaShort, 
    MetaInt, 
    MetaFloat, 
    MetaDouble 
}; 

union MetaUnion 
{ 
    char cValue; 
    short sValue; 
    int iValue; 
    float fValue; 
    double dValue; 
}; 

class MetaValue 
{ 
... 
private: 
    MetaValueType ValueType; 
    std::string StringValue; 
    MetaUnion VariantValue; 
}; 

MetaValue 클래스 현재 저장된 변형 값을 얻기위한 다양한 가져 오기 기능을 가지고 있지만,이 값에 대한 모든 쿼리를 만드는 경우의 큰 블록을 끝/else if 문을 사용하여 원하는 값을 찾습니다.

또한 문자열을 값으로 저장하고 다른 변형 유형을 가져 오기 위해 변환을 수행하는 방법을 살펴 보았습니다. 그러나이 경우에는 내부 문자열 파싱 및 오류 처리가 많이 발생합니다. 예쁘다면, 부동 소수점 값으로 정밀도와 데이터 손실 문제가 생길 수 있으며, 위에서 언급 한 문제라면/그 밖에도 쿼리를 제거하지 않아도됩니다.

누군가 표준 라이브러리를 사용하여 C++ 변형 데이터 형식에 사용할 클리너를 구현하거나 보았습니까?

+2

내가 설명하는 문제로 제목을 같이 분석 제안 할 수 있음? 아마도 "C++에서 변형 데이터를 저장하는 방법"과 같은 것일 수 있습니다. 나는 당신이 더 많은 반응을 얻을 것이라고 생각합니다! – jwfearn

+2

흠 ... 한 번에 제목을 이해했습니다. –

답변

26

Boost.Variant 또는 Boost.Any 일 수 있습니다.

추가 포인터와 마찬가지로 "유형 삭제"를 찾을 수 있습니다.

+0

Herb Sutter도이 답변을 제안합니다. http://herbsutter.com/2008/06/20/type-inference-vs-staticdynamic-typing/ – user79878

8

또한 C-ish 솔루션으로 넘어갈 수 있습니다.이 솔루션은 시스템의 이중 크기 *와 사용중인 유형의 열거 형을 무효화합니다. 합리적으로 깨끗하지만, 시스템의 원시 바이트를 완전히 편안하게 느끼는 사람을위한 솔루션입니다.

+1

void *는 꽤 악합니다. 가능한 경우보다 세련된 솔루션을 선호하십시오. –

+5

원시 메모리 작업에 익숙하다면 매우 우아한 솔루션입니다. –

+5

void 포인터가 우아하다는 것에 동의하지 않습니다. 타입 시스템을 우회하고 있습니다. 원시 메모리로 작업하는 것이 안심할 수 있습니다. 가능한 한 컴파일러에서 모든 도움을 얻으 려합니다. – lkristjansen

11

기존의 표준화 된 솔루션을 사용하는 Konrad의 대답이 자신 만의 버그가 발생하기 쉬운 버전을 작성하는 것보다 분명 바람직하지만, 부스트 변형은 특히 복사본 구성 및 메모리에 약간의 오버 헤드가 있습니다.

일반적인 사용자 접근 다음 변성 초기 패턴 :

  1. 가 '유형 ID'를 사용하는 일반도 (어느 열거로) 오브젝트 유형을 캡슐화 객체 또는 거점 인터페이스를 생성은 (바람직한) .
  2. 이제 Derived 클래스 템플릿을 사용하여 인터페이스를 구현하십시오.
  3. 서명과 templateized create 기능 팩토리 클래스를 만듭니다 :

template <typename _T> Base * Factory::create();

이 내부적으로 힙에 Derived<_T> 객체를 생성하고, 동적 캐스트 포인터를 retuns. 구현하고자하는 각 클래스에 대해 이것을 전문화하십시오.

마지막으로 Base * 포인터를 포함하는 Variant 랩퍼를 정의하고 템플리트 get 및 set 기능을 정의하십시오. getType(), isEmpty(), 할당 및 항등 연산자 등의 유틸리티 함수를 여기에서 적절하게 구현할 수 있습니다.

유틸리티 기능 및 공장 구현에 따라 지원되는 클래스는 할당 또는 복사 구성과 같은 일부 기본 기능을 지원해야합니다.

+0

다시 말해, 마이크로 초 수준의 타이밍이 중요하지 않다면 가능한 경우 부스트 클래스를 사용하십시오. – Fox

+0

FIFY : 나노초 수준. –

+2

:) API 사용 당 나노초 - 내 경험상 이와 같은 기본적인 구현이 합쳐집니다. – Fox

3

오랜 시간 동안 질문에 대답했지만, 기록을 위해 나는 QVariant도 이것을하고 싶습니다.

5

C++ 17은 현재 사용자가 찾고있는 정확히 std::variant입니다.

std::variant