2013-07-16 2 views
0

У меня есть приложение, которое использует mongodb в качестве базы данных back end и хочет, чтобы централизовать имена полей, используемые в коллекции mongo для доступа на стороне C++. Имена полей используются в различных частях приложения (сериализация, запрос и т. Д.), И я бы предпочел не использовать фактический жесткий код для названий полей во всех этих разных местах, чтобы облегчить обслуживание.C++ Глобальное сопоставление для полей базы данных mongo

Использование синглтона изначально пришло на ум, но я бы предпочел не использовать его. Я также играл с идеей использования boost-fusion для создания сопоставления типов с именами полей, но все типы были бы по существу пустыми структурами. Мысли о подходе?

ответ

0

Используйте перечисление с сериализации/десериализации - один перечисление в коллекции будет иметь смысл:

#include <string> 
#include <iostream> 
#include <boost/bimap.hpp> 

template<typename def, typename inner = typename def::type> 
class safe_enum : public def 
{ 
    inner val; 

public: 
    typedef typename def::type type; 
    safe_enum(type v) : val(v) {} 
    inner underlying() const { return val; } 

    friend bool operator == (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val == rhs.val; } 
    friend bool operator != (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val != rhs.val; } 
    friend bool operator < (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val < rhs.val; } 
    friend bool operator <= (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val <= rhs.val; } 
    friend bool operator > (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val > rhs.val; } 
    friend bool operator >= (const safe_enum & lhs, const safe_enum & rhs) { return lhs.val >= rhs.val; } 
}; 

class some_collection_fields_def 
{ 
public: 
    enum type { invalid, somename, anothername, morenames }; 
}; 

class some_collection_fields 
    : 
     public safe_enum<some_collection_fields_def> 
{ 
public: 
    typedef safe_enum<some_collection_fields_def> BaseType; 
public: 
    some_collection_fields(type v) 
     : 
      BaseType(v) 
    {} 
    some_collection_fields(const std::string& v) 
     : 
      BaseType(invalid) 
    { 
     *(this) = v; 
    } 
    some_collection_fields& operator =(const std::string& in) 
    { 
     string_bimap_type::right_map::const_iterator cit = string_bimap.right.find(in); 
     if (cit == string_bimap.right.end()) 
     { 
      throw std::domain_error(std::string(__func__) + ": Failed to convert from [" + in + "]"); 
     } 
     (*this) = cit->second; 
     return *this; 
    } 
    const std::string& as_string() const 
    { 
     string_bimap_type::left_map::const_iterator cit = string_bimap.left.find(this->underlying()); 
     if (cit == string_bimap.left.end()) 
     { 
      throw std::range_error(std::string(__func__) + ": Undefined value [" + std::to_string(this->underlying()) + "]"); 
     } 
     return cit->second; 
    } 
private: 
    typedef boost::bimap< type, std::string > string_bimap_type; 
    static string_bimap_type string_bimap_init() 
    { 
     string_bimap_type tmp_string_bimap; 
     tmp_string_bimap.insert(string_bimap_type::value_type(somename, "somename")); 
     tmp_string_bimap.insert(string_bimap_type::value_type(anothername, "anothername")); 
     tmp_string_bimap.insert(string_bimap_type::value_type(morenames, "morenames")); 
     return tmp_string_bimap; 
    } 
    static string_bimap_type string_bimap; 
}; 

some_collection_fields::string_bimap_type some_collection_fields::string_bimap = some_collection_fields::string_bimap_init(); 

std::ostream& operator <<(std::ostream& out, const some_collection_fields& in) 
{ 
    out << in.as_string(); 
    return out; 
} 

int main() 
{ 
    { 
     some_collection_fields field = some_collection_fields::somename; 
     std::cout << field << std::endl; 
     std::cout << field.as_string() << std::endl; 
     std::cout << field.underlying() << std::endl; 
    } 
    { 
     some_collection_fields field("anothername"); 
     std::cout << field << std::endl; 
     std::cout << field.as_string() << std::endl; 
     std::cout << field.underlying() << std::endl; 
    } 
} 

компиляции:

g++ -std=c++0x -o 17687554.a1 17687554.a1.cpp 

выход:

$ ./17687554.a1 
somename 
somename 
1 
anothername 
anothername 
2 

Примечания:

  1. safe_enum из here
  2. вы могли бы, вероятно, обобщать это с шаблоном
0

Я продолжал с подходом с использованием наддува фьюжн и перечислений.

enum ActivitySchemaEnum 
{ 
    DEFINITION, 
    NAME, 
    STATE, 
    START, 
    END 
}; 

template <ActivitySchemaEnum ACTSCHEMA_V> 
struct Field; 

typedef boost::fusion::map< 
    boost::fusion::pair<Field<DEFINITION>, char const*>, 
    boost::fusion::pair<Field<NAME>, char const*>, 
    boost::fusion::pair<Field<STATE>, char const*>, 
    boost::fusion::pair<Field<START>, char const*>, 
    boost::fusion::pair<Field<END>, char const*> 
> actinst_schema; 

actinst_schema const ActivitySchema(
    boost::fusion::make_pair<Field<DEFINITION> >("definition"), 
    boost::fusion::make_pair<Field<NAME> >("name"), 
    boost::fusion::make_pair<Field<STATE> >("state"), 
    boost::fusion::make_pair<Field<START> >("start"), 
    boost::fusion::make_pair<Field<END> >("end") 
); 

Затем в коде клиента я делать звонки как (простой вызов, но вы получите идею.)

const char* myFieldName = boost::fusion::at_key<Field<DEFINITION> >(ActivitySchema); 

использования Клиентского немного многословное, но я думаю, что это на самом деле довольно себя описывающий с что ты делаешь.

Смежные вопросы