C++のアプリケーションでは、私はCライブラリとインタフェースする必要があります。このライブラリには、それぞれ独自のAPIを持ついくつかのコンポーネントがあります。 APIは非常によく似ていて、関数の接頭辞と一部のハンドラ型だけが異なります。たとえば:Cの消費のためのC APIを包むための戦略
// bull component
void bull_create(bull_handle_t** handle, error_details_t* error_details);
void bull_destroy(bull_handle_t* handle, error_details_t* error_details);
void bull_get_data(bull_handle_t* handle, uint8_t* buffer, error_details_t* error_details);
// frog component
void frog_create(frog_handle_t** handle, error_details_t* error_details);
void frog_destroy(frog_handle_t* handle, error_details_t* error_details);
void frog_get_data(frog_handle_t* handle, uint8_t* buffer, error_details_t* error_details);
// bullfrog component
void bullfrog_create(bullfrog_handle_t** handle, error_details_t* error_details);
void bullfrog_destroy(bullfrog_handle_t* handle, error_details_t* error_details);
void bullfrog_get_data(bullfrog_handle_t* handle, uint8_t* buffer, error_details_t* error_details);
// NOTE: components can and will be added at any time following the same pattern.
これは、コードの重複を最小限に抑えながら、一般的な方法でC++で使用するために使用します。 だから、最初の単純なアプローチ:
class bull_backend
{
public:
...
void get_data (uint8_t* buffer)
{
error_details_t err;
bull_get_data(handle, buffer, &err);
}
...
private:
bull_handle_t* handle;
};
class frog_backend
{
public:
...
void get_data (uint8_t* buffer)
{
error_details_t err;
frog_get_data(handle, buffer, &err);
}
...
private:
frog_handle_t* handle;
};
class bullfrog_backend
{
public:
...
void get_data (uint8_t* buffer)
{
error_details_t err;
bullfrog_get_data(handle, buffer, &err);
}
...
private:
bullfrog_handle_t* handle;
};
かなりそれをカットしていません。私はC APIを複製するだけで、クラスの形になります。 異なるのは、Cエンティティを識別する接頭辞だけです。
私の心の次のものは、準備されていたマクロです。
#define GENERATE_BACKEND(...)
...
これはプレフィックスの代わりになります。しかし、私はそれが好きではありません。それは モダンなC++のような気がしません。
もう1つのことは、1つのクラステンプレート内のすべてのグループをグループ化し、 doタグをディスパッチするか、またはenable_ifを使用することです。
template <typename Component>
class backend
{
public:
...
template<typename = typename std::enable_if<std::is_same<Component, bull_component>::value>::type>
void get_data (uint8_t* buffer)
{
error_details_t err;
bull_get_data(handle, buffer, &err);
}
template<typename = typename std::enable_if<std::is_same<Component, frog_component>::value>::type>
void get_data (uint8_t* buffer)
{
error_details_t err;
frog_get_data(handle, buffer, &err);
}
template<typename = typename std::enable_if<std::is_same<Component, bullfrog_component>::value>::type>
void get_data (uint8_t* buffer)
{
error_details_t err;
bullfrog_get_data(handle, buffer, &err);
}
...
private:
typename Component::handle_type handle;
};
struct frog_component
{
using handle_type = frog_handle_t*;
};
struct bull_component
{
using handle_type = bull_handle_t*;
};
struct bullfrog_component
{
using handle_type = bullfrog_handle_t*;
};
using frog_backend = backend<frog_component>;
using bull_backend = backend<bull_component>;
using bullfrog_backend = backend<bullfrog_component>;
まだそれは正しく感じません。明らかなコード の複製以外に私を悩ますもう1つのことは、マクロバージョンを除いて:)、それは のCコンポーネントの追加でうまくスケーリングできません。
私はいつもより良いことがあるはずの印象を受けています。 だから、誰も、より現代的なC++の名前、技術の価値を知っている このような状況を処理するためのテクニックですか?
テンプレートと関数ポインタ? – Jarod42
私はdownvotesを理解していません。少なくとも礼儀正しく、説明してください。 – celavek
@ Jarod42あなたは例を挙げることができますか? – celavek