Can Boost Proto可以将结构适应于getter setter类型的API

时间:2016-07-13 19:39:51

标签: c++ templates boost boost-phoenix boost-proto

这似乎是一个常见的问题。我有两个需要粘合在一起的大量代码:一个使用简单的结构来保存数据,另一个使用只暴露getter / setter方法的API。

是否可以使用Boost.Proto定义一个映射,然后可以用它来自动生成调用getter / setter的代码?从概念上讲,似乎最困难的部分是要调用的函数名的合成,因为这将涉及编译时字符串连接。其他挑战涉及将枚举类型从一个映射到另一个以及自定义初始化或转换代码。

有一个解决这个问题的基于Proto的解决方案对于各种各样的人来说将是一个巨大的好处。

例如,我有一个类型如下的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,并让编译器为我生成重复代码。

我可以定义足够的Proto终端来编译这个构造函数:

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))
    ;
}

转换在概念上可以是一个简单的函数调用:

// 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);

这是一个丑陋的开始,但我现在感到困惑的是如何破坏名称以生成对getter和setter的调用。

这可能吗?解决方案是什么样的?

0 个答案:

没有答案