我有一个应用程序使用mongodb作为后端数据库,并希望集中在mongo集合中使用的字段名称,以便在C ++方面进行访问。字段名称用于应用程序的各个部分(序列化,查询等),我不希望在所有这些不同的位置实际硬编码字段名称以便于维护。
最初想到使用单身人士,但我宁愿不使用单身人士。我还玩弄了使用boost fusion来创建类型到字段名称的映射的想法,但这些类型基本上都是空结构。对方法的想法?
答案 0 :(得分: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 :(得分: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);
客户端的使用有点冗长,但我认为它实际上非常自我描述你在做什么。