我有一個使用mongodb作爲後端數據庫的應用程序,並且想要一種方法來集中在mongo集合中使用的字段名稱,以便在C++端訪問。字段名用於應用程序的各個部分(序列化,查詢等),我不希望在所有這些不同位置實際硬編碼字段名稱,以便於維護。mongo數據庫字段的C++全局映射
最初想起使用單例,但我不想使用單例。我也玩弄了使用boost融合來創建類型到字段名稱的映射的想法,但是這些類型實際上都是空的結構。關於方法的思考?
我有一個使用mongodb作爲後端數據庫的應用程序,並且想要一種方法來集中在mongo集合中使用的字段名稱,以便在C++端訪問。字段名用於應用程序的各個部分(序列化,查詢等),我不希望在所有這些不同位置實際硬編碼字段名稱,以便於維護。mongo數據庫字段的C++全局映射
最初想起使用單例,但我不想使用單例。我也玩弄了使用boost融合來創建類型到字段名稱的映射的想法,但是這些類型實際上都是空的結構。關於方法的思考?
使用序列化/反序列化的枚舉 - 每收集一個枚舉將使意義:
#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
注:
我一直在使用升壓融合和枚舉的方法大概概括這一點。
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);
客戶端的使用是有點冗長,但我認爲它實際上是非常強的自我與描述你在做什麼。