これはよくある問題のようです。1 つは単純な構造体を使用してデータを保持し、もう 1 つは getter/setter メソッドのみを公開する API を持っています。
Boost.Proto を使用して、ゲッター/セッターを呼び出すコードを自動生成するために使用できるマッピングを定義することは可能ですか? 概念的に、最も難しいと思われる部分は、呼び出す関数名の合成です。これには、コンパイル時の文字列連結が含まれるためです。その他の課題には、列挙型の一方から他方へのマッピング、およびカスタムの初期化または変換コードが含まれます。
この問題を解決するドロップイン プレースの 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);
それは醜いスタートですが、ゲッターとセッターへの呼び出しを生成するために名前を壊す方法に困惑しています。
これは可能ですか?解決策はどのようになりますか?