如果你愿意使用预处理器为你生成代码,你可以依赖Boost.Preprocessor。例如,您可以按照以下方式做一些事情:
#define GET_TYPE( pair ) BOOST_PP_TUPLE_ELEM( 2, 0, pair )
#define GET_NAME( pair ) BOOST_PP_TUPLE_ELEM( 2, 1, pair )
#define DECLARE_MANDATORY( r, data, elem ) GET_TYPE( elem ) GET_NAME( elem );
#define DECLARE_MANDATORY_ATTRIBUTES( attributes ) \
BOOST_PP_SEQ_FOR_EACH( DECLARE_MANDATORY, ~, attributes )
#define DECLARE_OPTIONAL( r, data, elem ) boost::optional< GET_TYPE( elem ) > GET_NAME( elem );
#define DECLARE_OPTIONAL_ATTRIBUTES( attributes ) \
BOOST_PP_SEQ_FOR_EACH( DECLARE_OPTIONAL, ~, attributes )
#define MANDATORY_ACCESSORS( r, data, elem ) \
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ) = value; } \
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return GET_NAME( elem ); }
#define DEFINE_MANDATORY_ACCESSORS( attributes ) \
BOOST_PP_SEQ_FOR_EACH( MANDATORY_ACCESSORS, ~, attributes )
#define OPTIONAL_ACCESSORS( r, data, elem ) \
BOOST_PP_CAT( void set_, GET_NAME( elem ) ) (GET_TYPE( elem ) const & value) { GET_NAME( elem ).reset(value); } \
GET_TYPE( elem ) BOOST_PP_CAT( get_, GET_NAME( elem ) ) () const { return *GET_NAME( elem ); }
#define DEFINE_OPTIONAL_ACCESSORS( attributes ) \
BOOST_PP_SEQ_FOR_EACH( OPTIONAL_ACCESSORS, ~, attributes )
class Book
{
#define BOOK_MANDATORY_ATTRIBUTES ((std::string, title))
#define BOOK_OPTIONAL_ATTRIBUTES ((std::string, author)) ((std::string, secondaryAuthor))
public:
DECLARE_MANDATORY_ATTRIBUTES( BOOK_MANDATORY_ATTRIBUTES )
DECLARE_OPTIONAL_ATTRIBUTES( BOOK_OPTIONAL_ATTRIBUTES )
DEFINE_MANDATORY_ACCESSORS( BOOK_MANDATORY_ATTRIBUTES )
DEFINE_OPTIONAL_ACCESSORS( BOOK_OPTIONAL_ATTRIBUTES )
};
int main()
{
Book b;
b.set_title("H2G2");
std::cout << b.get_title();
b.set_author("Douglas Adams");
std::cout << b.get_author();
}
您可以创建另一个宏来为您的序列化函数生成代码,利用 [ boost::optional
](http://www.boost.org/libs/optional] 来测试是否设置了可选属性。
如果您不想进行代码生成,您将无法自动获取属性的访问器。但是,序列化方面可以更经典地处理,例如通过为所有属性使用公共基类。这样,您可以将它们存储在容器中,并遍历它们以要求它们序列化自己:
struct Attribute
{
virtual QString serializePlainText() = 0;
};
// Generic attribute for the most common cases
template <typename T>
class MandatoryAttribute : public Attribute
{
T value;
public:
std::string serializePlainText()
{
return boost::lexical_cast<std::string>(value);
}
};
// Generic attribute for the most common cases
template <typename T>
class OptionalAttribute : public Attribute
{
boost::optional<T> value;
public:
bool isSet() const { return value; }
std::string serializePlainText()
{
return isSet() ?
boost::lexical_cast<std::string>(value) :
"";
}
};