2011-12-20 2 views
6

C++을 사용하여 여러 데이터 형식을 처리하기 위해 일반 컨테이너 클래스를 만들려고합니다. 그것은 다양한 솔루션에 공통적 인 문제입니다. 그러나 저는 파이썬이나 VB/VBA와 같은 언어로 익숙해 진만큼 직관적 인 것으로 생각하지 않았습니다 ...C++에서 여러 데이터 형식의 일반 컨테이너

그럼 내 시나리오는 다음과 같습니다.

저는 여러 요소의 여러 데이터 형식을 저장하는 데 사용하는 boost :: any를 기반으로 DataContainer 클래스를 작성했습니다. 나는 선언지도를 사용

std::list<boost::any> 

/관리 목록에 액세스하기위한 편의 기능과 함께 : DataContainer이 형식의 개체를 캡슐화하는 클래스입니다

std::map<std::string, DataContainer* (or DataContainerBase*)> 

.

그러나 결국 데이터 컨테이너 외부에서 형식 변환을해야합니다. 내가 접근,지도에서 INT 값의 목록을 저장한다면

예를 들어, 그들에게 필요 : 차라리 부스트 코드는 데이터 컨테이너 구조 내에 완전히 포함 할 것

int value = boost::any_cast<int>(map["myValue"]->get()); 

, 그래서

int value = map["myValue"]->get(); 

하거나, 최악의 경우 : 난 단지 유형 필요 물론

int value = map["myValue"]->get<int>(); 

을, 나는 공동() 함수

int value = map["myValue"]->get(TYPE_INT); 

또는 유형 특정 GET 쓰기 : ULD 내 데이터 유형을 열거하고 뭔가를 할

getInt(), getString(), getBool() ... 
마지막 두 옵션에 대한 문제는 그들이 나를 필요로하는, 다소 융통성이 있다는 것입니다

컨테이너에 저장하려는 각 유형을 명시 적으로 선언합니다. any_cast 솔루션 (구현 및 작동)은 괜찮습니다. 단지 ... 우아하지 않습니까? 나는 몰라. 외부에서 내부 역학을 사용할 필요가 없어야합니다.

DataContainer 멤버 함수를 호출 할 때 값 유형을 선언하지 않고 값을 전달하면 void * 솔루션 (명백한 이유 때문에 바람직하지 않음)이 필요하며 "get()"호출을 사용하면 기본적으로 허용되지 않는 기본 클래스 수준에서 정의 된 "가상 템플릿"멤버 함수를 (지금까지 말할 수있는 한) 요구합니다.

그렇듯이 나는 실행할 수있는 솔루션이 있으며, 실제로이 경우 내 사용은 대부분의 솔루션이 잘 작동 할 수있을 정도로 범위가 충분하지 않습니다. 하지만 아마도 일반적인 멀티 유형 데이터 컨테이너를 관리하는보다 유연한 방법이 있는지 궁금합니다.이 몇 가지 설탕 소개합니다

+1

부스트'에 보라 : 어쩌면 너무 variant'이 당신이 찾고있는 무엇 (?). – Kos

+0

그냥'std :: map '에 무슨 문제가 있습니까? –

+0

또한,'DataContainer'가 당신의 통제하에 있기 때문에 왜 그냥 멤버 함수를 추가하지 않을까요? template get_as() {return boost :: any_cast (get()); }'any-cast를 래핑 하시겠습니까? 그런 다음 제안한대로'm [ "abc"] -> get_as ()'이라고 말할 수 있습니다. 충분히 간단하게 들립니다. –

답변

6

:

int value = boost::any_cast<int>(map["myValue"]->get()); 

는 다음 프록시 개체를 반환하는 get() 기능을 할 수 있습니다를, + 정의 -이 같은 : 다음

struct Proxy { 
    boost::any& value; 
    Proxy(boost::any& value) : value(value) {} 

    template<typename T> 
    operator T() { 
     return boost::any_cast<T>(value); 
    } 
}; 

이 구문은 다음과 같이 작동합니다.

int value = map["myValue"]->get(); 
// returns a proxy which gets converted by any_cast<int> 

그러나 나는 분명하고 단순한 (위의 템플릿 변환 연산자와 동일하지만 않음)

int value = map["myValue"]->get<int>(); 

여기 get 템플릿 방식으로 프록시 객체를 반환하지만, 템플릿 방식 자체 않는다 : 그 문법을 사용한다.

+0

@JoelGraff 만약 내가 많이 벗어나지 않는다면, 자동 템플릿 매개 변수 공제 덕분에 두 번째 경우에'get()'를 얻을 수도 있습니다. 간접 지정의 한 수준을 저장하려면 DataCOntainer를 직접 저장하는 것이 좋습니다. 리스트 인스턴트 그 자체가 꽤 작아서 (헤드 만), 엘레멘트는 힙에있다. – ted

+0

자동 매개 변수 공제는 반환 형식이 아닌 매개 변수에만 적용됩니다. – Kos

+0

당신이 맞아, 이것 좀 봐 http://stackoverflow.com/a/2612979/258418, 또한 해결 방법을 통해 하나의 유형을 떠날 방법을 지적하지만, 이것은 다소 복잡한 유형의 경우에만 흥미 롭습니다 – ted

1

오늘 원하는 소스 코드를 작성했습니다. 나는이 질문이 너무 오래되었다는 것을 알고 있지만 아마도이 작은 코드는 누군가에게 도움이 될지도 모른다. 그것은 주로 boost : any를 기반으로합니다.

/* 
* AnyValueMap.hpp 
* 
* Created on: Jun 3, 2013 
*  Author: alvaro 
*/ 

#ifndef ANYVALUEMAP_HPP_ 
#define ANYVALUEMAP_HPP_ 

#include <map> 
#include <boost/any.hpp> 

using namespace std; 

template <class T> 
class AnyValueMap { 

public: 
    AnyValueMap(){} 

    virtual ~AnyValueMap(){} 

private: 
    map<T, boost::any> container_; 

    typedef typename map<T, boost::any>::iterator map_iterator; 
    typedef typename map<T, boost::any>::const_iterator map_const_iterator; 

public: 

    bool containsKey(const T key) const 
    { 
     return container_.find(key) != container_.end(); 
    } 

    bool remove(const T key) 
    { 
     map_iterator it = container_.find(key); 
     if(it != container_.end()) 
     { 
      container_.erase(it); 
      return true; 
     } 
     return false; 
    } 

    template <class V> 
    V getValue(const T key, const V defaultValue) const 
    { 
     map_const_iterator it = container_.find(key); 
     if(it != container_.end()) 
     { 
      return boost::any_cast<V>(it->second); 
     } 
     return defaultValue; 
    } 

    template <class V> 
    V getValue(const T key) const 
    { 
     return boost::any_cast<V>(container_.at(key)); 
    } 

    template <class V> 
    void setValue(const T key, const V value) 
    { 
     container_[key] = value; 
    } 
}; 

#endif /* ANYVALUEMAP_HPP_ */ 

간단한 사용 예 :

AnyValueMap<unsigned long> myMap; 
myMap.setValue<double>(365, 1254.33); 
myMap.setValue<int>(366, 55); 
double storedDoubleValue = myMap.getValue<double>(365); 
int storedIntValue = myMap.getValue<int>(366); 
관련 문제