C++ 可以将Proto-adapt结构提升到getter-setter类型API
这似乎是一个常见的问题。我有两组大量的代码需要粘在一起:一组使用简单的结构来保存数据,另一组有只公开getter/setter方法的api 是否可以使用Boost.Proto定义一个映射,然后使用该映射自动生成调用getter/setter的代码?从概念上讲,最困难的部分似乎是要调用的函数名的合成,因为这将涉及编译时字符串连接。其他挑战包括将枚举类型从一种映射到另一种以及自定义初始化或转换代码 拥有一个基于原型的解决方案来解决这个问题,将为各种各样的人带来巨大的好处 例如,我有一个API,其类型如下:C++ 可以将Proto-adapt结构提升到getter-setter类型API,c++,templates,boost,boost-phoenix,boost-proto,C++,Templates,Boost,Boost Phoenix,Boost Proto,这似乎是一个常见的问题。我有两组大量的代码需要粘在一起:一组使用简单的结构来保存数据,另一组有只公开getter/setter方法的api 是否可以使用Boost.Proto定义一个映射,然后使用该映射自动生成调用getter/setter的代码?从概念上讲,最困难的部分似乎是要调用的函数名的合成,因为这将涉及编译时字符串连接。其他挑战包括将枚举类型从一种映射到另一种以及自定义初始化或转换代码 拥有一个基于原型的解决方案来解决这个问题,将为各种各样的人带来巨大的好处 例如,我有一个API,其类型
// These classes use getters/setters.
class Wheel
{
int number_of_lugnuts_;
public:
void initialize_wheel(bool);
void set_number_of_lugnuts(int);
int get_number_of_lugnuts();
};
class Engine
{
public:
enum Gas_type_t {
Unleaded,
Premium
};
private:
Gas_type_t gas_type_;
public:
void initialize_engine(bool);
void set_gas_type(Gas_type_t);
Gas_type_t get_gas_type();
};
虽然我还有数百万行代码,在简单的直接访问结构中包含相同的数据:
// This code has simple data structures.
struct Car
{
// These POD members are used by a large body of existing code.
int lugnut_count;
enum FUEL_TYPES {
NORMAL_FUEL,
HI_OCTANE
};
FUEL_TYPES fuelType;
};
现在,传统的方法是添加大量转换器:
// The manual way to accomplish this for only the Wheel API.
// This has to be repeated similarly for the Engine API.
void convert_to_wheel(Wheel& w)
{
w.initialize_wheel(true); // how can initialization be handled?
w.set_number_of_lugnuts(lugnut_count);
}
void convert_from_wheel(Wheel& w)
{
lugnut_count = w.get_number_of_lugnuts();
}
但是,以Boost.Spirit的风格,我想使用Proto创建一个EDSL,允许我指定映射,并让编译器为我生成重复代码
我可以定义足够的原型终端来编译此构造函数:
Car()
{
// So can we define an API mapping like this?
// Would strings be the only way to accomplish this?
// This appears structurally similar to how Spirit grammars are defined.
// This is a very rough attempt because it's unclear if this is possible.
define_api_mapping<Wheel>
(initialization_code((_dest_ ->* &Wheel::initialize_wheel)(true)))
(map_member(lugnut_count) = map_getset("number_of_lugnuts"))
;
define_api_mapping<Engine>
(initialization_code((_dest_ ->* &Engine::initialize_engine)(true)))
(map_member(fuelType) = map_getset("gas_type"))
;
define_enum_mapping<FUEL_TYPES>
(enum_value(NORMAL_FUEL) = enum_value(Engine::Unleaded))
(enum_value(HI_OCTANE) = enum_value(Engine::Premium))
;
}
这是一个丑陋的开始,但我现在很困惑如何篡改名称来生成对getter和setter的调用
这可能吗?解决方案会是什么样子?我不相信最终结果会比手动映射好(如果您有什么东西可以生成,就生成代码)。此外,我发现“将汽车转换为车轮”(即隐式释放所有其他信息)的概念是可疑的。至少,它的名字不好,也许名字不好。但每个人都面临着这样的情况:两个API相似,但可能处于不同的抽象级别。事实上,我现在要面对它了!编写一堆样板代码即使不是完全令人沮丧,也只是一种负担。必须有一种自动化的方式,也许有。但在缺乏语言反思的情况下,我不会花太多时间试图将其纳入TMP。我去过那里。那样做了。顺便说一下,看看像AutoMapper这样的流行库,它们可以为灵感和概念命名。祝你好运我怀疑C++编译器在编译时不能合成方法调用名称,但是即使我们必须显式指定GETT/SETER成员函数,该解决方案仍然会有巨大的好处。接下来的问题是,如何综合执行实际转换所需的方法…谷歌“预处理器标记粘贴”。与Boost.PP一起,您应该有所收获。我不确定它给你带来了什么,只是用脚本语言编写脚本
// Declare some objects.
Car c;
Engine e;
Wheel w1, w2;
// Set some values.
c.lugnut_count = 20;
// Convert the old fashioned way.
c.convert_to_wheel(w1);
// Convert the new way.
convert(c, w2);