Я столкнулся с двумя проблемами, пытаясь заставить это скомпилировать:
- У вас не может быть контейнера ссылок
- Макросы и фигурные скобки плохо смешиваются
Чтобы исправить # 1, используйте вместо этого указатель:
std::unordered_map<std::string, typeBase*>
Чтобы исправить # 2, используйте вспомогательную функцию для инициализации карты:
template <typename... Ts>
std::unordered_map<std::string, typeBase*> build_properties(Ts&&... args) {
return std::unordered_map<std::string, typeBase*> { { args.first, args.second }... };
}
Тогда цель состоит в том, чтобы сгенерировать this с макросами:
build_properties(
std::make_pair("mInt", &mInt_),
std::make_pair("mStr", &mStr_)
)
Что немного проще и успешно компилируется:
#define MODEL_GENERATE_MAP_ITEM(Name, Type) std::make_pair( #Name, &Name##_ )
#define MODEL_UNWRAP_MAP_ITEM(Unused1, Unused2, Arg) MODEL_GENERATE_MAP_ITEM Arg
#define MODEL_GENERATE_MAP_ITEMS(Args) \
BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MODEL_UNWRAP_MAP_ITEM,,Args))
#define MODEL_DECLARE(...) \
std::unordered_map<std::string, typeBase*> properties = build_properties( \
MODEL_GENERATE_MAP_ITEMS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
);
// Generate model with this line
MODEL_DECLARE((mInt, typeInt), (mStr, typeStr))
Более напрямую связано на ваш вопрос, макрос BOOST_PP_VARIADIC_TO_SEQ
добавляет пару круглых скобок вокруг ваших аргументов:
(mInt, typeInt), (mStr, typeStr) ==> ((mInt, typeInt)) ((mStr, typeStr))
Поэтому, когда BOOST_PP_SEQ_TRANSFORM
генерирует свои макросы, аргумент, сгенерированный для каждого макроса преобразования, имеет круглые скобки, например (mInt, typeInt)
. Чтобы избавиться от этих скобок, я добавил этот макрос:
MODEL_UNWRAP_MAP_ITEM(Unused1, Unused2, Arg) MODEL_GENERATE_MAP_ITEM Arg
, который при замене Arg
:
MODEL_GENERATE_MAP_ITEM (mInt, typeInt)
, который в последний раз преобразуется в:
std::make_pair( "mInt", mInt_ )
Демонстрация: https://godbolt.org/z/5fyo3N
Обновление
Чтобы заставить работать обновленный код, мне пришлось внести 3 изменения:
- Вместо
BOOST_PP_SEQ_TRANSFORM
используйте BOOST_PP_SEQ_FOR_EACH
. Первый делает карту для каждого элемента и превращает ее обратно в SEQ
: BOOST_PP_SEQ_TRANSFORM(ADD_1, , (a)(b)) ==> (a+1)(b+1)
, в то время как BOOST_PP_SEQ_FOR_EACH
выполняет операцию отображения, но не добавляет обратно круглые скобки: BOOST_PP_SEQ_TRANSFORM(ADD_1, , (a)(b)) ==> a+1 b+1
Поскольку у вас есть эта set_mInt
функция, вам нужно добавить оператор присваивания в typeBase_<T>
:
typeBase_& operator =(const typeBase_& that) { value_ = that.value_; return *this; }
MODEL_GENERATE_VARS
должен быть до объявления карты так mInt_
и друзья видны
Все вместе:
#define MODEL_GENERATE_MAP_ITEM(Name, Type) std::make_pair( #Name, &Name##_ )
#define MODEL_UNWRAP_MAP_ITEM(Unused1, Unused2, Arg) MODEL_GENERATE_MAP_ITEM Arg
#define MODEL_GENERATE_MAP_ITEMS(Args) BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(MODEL_UNWRAP_MAP_ITEM,,Args))
// Macro used to declare vars and setters
#define MODEL_GENERATE_VAR(Name, Type) Type Name##_; \
void set_##Name(const Type& Name) { \
Name##_ = Name; \
changed_list_.insert(#Name); \
};
#define MODEL_UNWRAP_VAR(Unused1, Unused2, Arg) MODEL_GENERATE_VAR Arg
#define MODEL_GENERATE_VARS(Args) BOOST_PP_SEQ_FOR_EACH(MODEL_UNWRAP_VAR,,Args)
// Macro to generate model
#define MODEL_DECLARE(...) \
MODEL_GENERATE_VARS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
std::unordered_map<std::string, typeBase*> properties_ = build_properties( \
MODEL_GENERATE_MAP_ITEMS(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
);
// Generate model
MODEL_DECLARE((mInt, typeInt), (mStr, typeStr))
Демо: https://godbolt.org/z/bDDe94