2012-12-13 2 views
1

XML 문자열을 읽고 일부 구조체 멤버를 XML 파일의 특성 키와 일치하는 값으로 채우는 C++를 작성했습니다. 이 순간의 첫 번째 패스는 키 - 값 쌍의 stl :: unordered_map을 만듭니다. 다음 단계는 값 문자열을 해석하여 대상 유형으로 반환하여 구조체에 저장합니다. 일부 유형은 약간 복잡하지만 변환 할 수있는 메소드가 있습니다.함수 테이블로 mpl :: vector 사용

내가 원하는 것은 mpl :: vector를 사용하여 get_value_ * 메소드를 사용하여 키를 구조체 멤버에 매핑하여 값을 변환하는 것입니다. 나는 조금 비슷하게 보일 것이라고 생각한다 :

typedef boost::mpl mpl; 
using namespace std; 

template<string K, typename T, T& dest, boost::function<void(MapTypePtr, string, T& dest)> > 
struct MapperRow {}; 

struct Mapper : mpl::vector< 
    MapperRow < "death_star_radius", Length, death_star.radius, get_value_units >, 
    MapperRow < "death_star_energy", Energy, death_star.energy, get_value_units >, 
    MapperRow < "operational",  bool, death_star.operational, get_value_simple >, 
    MapperRow < "num_tie_fighters", int, death_star.tie_fighers, get_value_simple > 
> {}; 

길이와 에너지 유형은 boost :: units :: quantity의 typedef이다.

부스트 메타 프로그래밍을 사용할 수 있습니까? 내가 올바른 길을 가고 있다면 어떻게 달릴 수 있습니까? mpl :: vector를 반복 할 필요가 있습니까?

+0

,하지만 당신은 할 수 템플릿 선언에서 문자열처럼 클래스를 사용하지 마십시오. 이는 'bool'또는 'unsigned'와 같은 기본 유형에서만 작동합니다. – Peter

+0

어떻게 든 그것을하는 mpl 래퍼 유형이있을 수 있습니다? 나는 불가능한 것을 요구하고 있을지도 모르지만 부스트 상태 머신과 비슷한 것을 보았 기 때문에 나는 가까이 갈 수 있기를 바라고있다. – MattSmith

+0

예, 방법이 있습니다. 꽤 힘들지는 않습니다 (인자로 많은 문자를 가진 템플릿을 사용하십시오). 이를 위해 코드 생성기를 사용하는 것이 더 쉽다는 것을 알았습니다. 코드 생성기는 이미 XML이 있고 코드를 생성하기 위해 xsl 또는 다른 종류의 변환기가 필요하기 때문에 자신의 경우 간단 할 수도 있습니다. – Peter

답변

1

이것은 확실히 가능합니다 (아래 참조). 문제가 될만한 가치가 있는지 확신 할 수 없습니다. 상속 및 다형성과 함께 간단한 접근 방식을 사용할 수 없습니까?

// MapperRow holds the necessary parsing informations: type of the member, 
// type of the object, pointer to the appropriate member, parsing function 
template<typename Type, typename Clazz, Type Clazz::*Member, 
     void (*Parser)(const std::string &, Type &)> 
struct MapperRow 
{ 
    typedef Type type; 
    typedef Clazz clazz; 
    typedef Type Clazz::*memberType; 
    static const memberType member; 
    typedef void (*parserType)(const std::string &, Type &); 
    static const parserType parser; 
}; 

template <typename Type, typename Clazz, Type Clazz::*Member, 
      void (*Parser)(const std::string &, Type &)> 
const typename MapperRow<Type, Clazz, Member, Parser>::memberType 
    MapperRow<Type, Clazz, Member, Parser>::member = Member; 

template <typename Type, typename Clazz, Type Clazz::*Member, 
      void (*Parser)(const std::string &, Type &)> 
const typename MapperRow<Type, Clazz, Member, Parser>::parserType 
    MapperRow<Type, Clazz, Member, Parser>::parser = Parser; 


// fill iterates over a map key->MapperRow, trying to find the given key. 
// if found, it calls the parsing function, otherwise it asserts false (should 
// probably throw an exception instead) 
template <typename Clazz, typename First, typename Last> 
struct fill_impl 
{ 
    static void apply(Clazz &obj, const std::string &key, 
         const std::string &value) 
    { 
     typedef typename mpl::deref<First>::type entry; 
     static const char *curKey = 
      mpl::c_str< typename 
       mpl::first<entry>::type 
      >::value; 

     if (key == curKey) 
     { 
      typedef typename mpl::second<entry>::type Row; 

      Row::parser(value, obj.*Row::member); 
     } 
     else 
     { 
      fill_impl< 
       Clazz, typename 
       mpl::next<First>::type, 
       Last 
      >::apply(obj, key, value); 
     } 
    } 
}; 

template <typename Clazz, typename Last> 
struct fill_impl<Clazz, Last, Last> 
{ 
    static void apply(Clazz &obj, const std::string &key, 
         const std::string &value) 
    { 
     assert(false && "key not found"); 
    } 
}; 

template <typename Map, typename Clazz> 
void fill(Clazz &obj, const std::string &key, const std::string &value) 
{ 
    fill_impl< 
     Clazz, typename 
     mpl::begin<Map>::type, typename 
     mpl::end<Map>::type 
    >::apply(obj, key, value); 
} 

샘플 사용 :

그럼에도 불구하고

, 여기 Boost.MPL를 사용하여 작업 솔루션이다 나는 아직 질문을 이해하지

template <typename T> 
void get_value_units(const std::string &str, T &value) 
{ 
    value = T::from_value(boost::lexical_cast<typename T::value_type>(str)); 
} 

template <typename T> 
void get_value_simple(const std::string &str, T &value) 
{ 
    value = boost::lexical_cast<T>(str); 
} 

typedef boost::units::quantity<boost::units::si::energy> Energy; 
typedef boost::units::quantity<boost::units::si::length> Length; 

struct DeathStar 
{ 
    Length radius; 
    Energy energy; 
    bool operational; 
    int tie_fighters; 
}; 

// Could be clearer with MPLLIBS_STRING* 
typedef mpl::map< 
    mpl::pair< 
     mpl::string<'deat','h_st','ar_r','adiu','s'>, 
     MapperRow< Length , DeathStar, &DeathStar::radius, 
        &get_value_units<Length> > >, 
    mpl::pair< 
     mpl::string<'deat','h_st','ar_e','nerg','y'>, 
     MapperRow< Energy, DeathStar, &DeathStar::energy, 
        &get_value_units<Energy> > >, 
    mpl::pair< 
     mpl::string<'oper','atio','nal'>, 
     MapperRow< bool, DeathStar, &DeathStar::operational, 
        &get_value_simple<bool> > >, 
    mpl::pair< 
     mpl::string<'num_','tie_','figh','ters'>, 
     MapperRow< int, DeathStar, &DeathStar::tie_fighters, 
        &get_value_simple<int> > > 
> death_star_map; 

int main() 
{ 
    DeathStar ds; 
    fill<death_star_map>(ds, "death_star_radius", "12"); 
    fill<death_star_map>(ds, "death_star_energy", "34"); 
    fill<death_star_map>(ds, "operational", "1"); 
    fill<death_star_map>(ds, "num_tie_fighters", "56"); 

    std::cout << "Radius: " << ds.radius << '\n'; 
    std::cout << "Energy: " << ds.energy << '\n'; 
    std::cout << "Operational: " << std::boolalpha << ds.operational << '\n'; 
    std::cout << "Tie fighters: " << ds.tie_fighters << '\n'; 
} 

* MPLLIBS_STRING

+0

답변 해 주셔서 감사합니다. 아니 그게 문제가 가치가 아니지만 나를 위해 그것이 가능해야하고 내가 mpl을 이해하는 데 도움이 될 것 같았다. 나는 당신의 대답을 중재하고 내가 깨달음을 얻는지를 볼 것입니다! – MattSmith

관련 문제