我有一个使用 mongodb 作为后端数据库的应用程序,并且想要一种方法来集中在 mongo 集合中使用的字段名称,以便在 C++ 方面进行访问。字段名称用于应用程序的各个部分(序列化、查询等),我不希望在所有这些不同位置对字段名称进行实际硬编码以方便维护。
最初想到使用单例,但我不想使用单例。我还玩弄了使用 boost fusion 来创建类型到字段名称的映射的想法,但这些类型本质上都是空结构。关于方法的想法?
使用带有序列化/反序列化的枚举 - 每个集合一个枚举是有意义的:
#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);
客户端使用有点冗长,但我认为它实际上是用你正在做的事情进行自我描述。