In einer C++ - App muss ich eine Schnittstelle mit einer C-Bibliothek. Diese Bibliothek hat mehrere Komponenten mit jeweils einer eigenen API. Die APIs sind sehr ähnlich und unterscheiden sich nur im Präfix der Funktionen und in einem Handler-Typ. Beispiel:Strategien zum Wrappen von C-API für C++ - Verbrauch
Ich möchte dies für C++ - Verbrauch in einer generischen Weise mit minimaler Code-Duplizierung umschließen. So wird zuerst der naive Ansatz:
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;
};
Das nicht ganz es geschnitten. Ich werde nur die C-API duplizieren, aber jetzt in Form von Klassen. Das einzige, was anders ist, ist nur das Präfix, das die C-Entitäten identifiziert.
Die nächste Sache in meinem Kopf war ein, vorbereitet sein, ein Makro, z.
#define GENERATE_BACKEND(...)
...
das würde nur für das Präfix ersetzen. Aber das mag ich nicht. Es fühlt sich nicht wie moderne C++ an.
Eine andere Sache, die ich tun könnte, ist alles in einer Klassenvorlage zu gruppieren und tun Tag senden oder verwenden Sie enable_if, z.
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>;
Noch fühlt es sich nicht richtig an. Eine andere Sache, die mich neben dem scheinbaren Code Duplikation stört, ist, dass, abgesehen von der Makro-Version :), sie nicht schön mit die Zugabe von C-Komponenten skalieren.
Ich habe immer den Eindruck, dass es etwas anderes geben muss, was besser ist. Kennt also jemand eine bessere, würdigere der modernen C++ - Name, Technik diese Art von Situation zu behandeln?
Vorlage und Funktionszeiger? – Jarod42
Ich verstehe die Downvotes nicht. Bitte sei wenigstens höflich und erkläre es. – celavek
@ Jarod42 könnten Sie ein Beispiel geben? – celavek