2013-07-16 55 views
0

我有一個使用mongodb作爲後端數據庫的應用程序,並且想要一種方法來集中在mongo集合中使用的字段名稱,以便在C++端訪問。字段名用於應用程序的各個部分(序列化,查詢等),我不希望在所有這些不同位置實際硬編碼字段名稱,以便於維護。mongo數據庫字段的C++全局映射

最初想起使用單例,但我不想使用單例。我也玩弄了使用boost融合來創建類型到字段名稱的映射的想法,但是這些類型實際上都是空的結構。關於方法的思考?

回答

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); 

客戶端的使用是有點冗長,但我認爲它實際上是非常強的自我與描述你在做什麼。