2016-03-23 13 views
-2

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++の名前、技術の価値を知っている このような状況を処理するためのテクニックですか?

+1

テンプレートと関数ポインタ? – Jarod42

+1

私はdownvotesを理解していません。少なくとも礼儀正しく、説明してください。 – celavek

+0

@ Jarod42あなたは例を挙げることができますか? – celavek

答えて

3

私が考えていることは、

template <typename H> using create_t = void (*)(H**, error_details_t*); 
template <typename H> using destroy_t = void (*)(H*, error_details_t*); 
template <typename H> using get_data_t = void (*)(H*, uint8_t* buffer, error_details_t*); 

template <typename H, 
      create_t<H> create, 
      destroy_t<H> destroy, 
      get_data_t<H> get_data> 
class backend 
{ 
    backend() { error_details_t err; create(&handle, err);} 
    ~backend() { error_details_t err; destroy(handle, err);} 

    backend(const backend&) = delete; 
    backend& operator =(const backend&) = delete; 
    backend(backend&&) = delete; 
    backend& operator =(backend&&) = delete; 

    void get_data(uint8_t* buffer) 
    { 
     error_details_t err; 
     get_data(handle, buffer, &err); 
    } 

private: 
    H* handle = nullptr; 
}; 

using bull = backend<bull_handle_t, &bull_create, &bull_destroy, &bull_get_data>; 
using frog = backend<frog_handle_t, &frog_create, &frog_destroy, &frog_get_data>; 
using bullfrog = backend<bullfrog_handle_t, 
         &bullfrog_create, 
         &bullfrog_destroy, 
         &bull_get_data>; 

はたぶんerror_details_tがメンバーになることができ あります。また、エラーを処理する必要があります。

+0

これは本当に面白いです。私はそれをさらに働かせることができると思う。私はすでに関数ポインタについて考えていましたが、どうやってそれらを "どのように"組み合わせるかはわかりませんでした。 – celavek

+0

それを実装し、それが動作します。ありがとう – celavek

1

私はJarod42が何か

template <typename T> 
class component 
{ 
private: 
    typedef void (*destroyMethod)(T*,error_details_t*); 
    ... 
public: 
    component(destroyMethod,...) 
    { 
     destroy = destroyMethod; 
     ... 
    } 
    void Destroy() 
    { 
     error_details_t err; 
     destroy(handle, err); 
    } 
    ... 
private: 
    destroyMethod destroy; 
    T * handle; 
}; 

を暗示した@、その後のようなものでインスタンス化することを考えています:

component<bull_handle_t> yourBull(bull_destroy, ...) 

そして、あなたはおそらく、いくつかの余分な作業

+0

しかし、APIには複数の機能があります。私は関数ポインタをそれぞれとすべての人に渡すべきですか? APIにもっと多くの機能を追加すれば、それはどのようにスケールされますか? – celavek

+0

コンポーネントクラスがそれぞれのタイプを反映しなければならない場合、異なるタイプのインターフェースが互いに発散しない限り、スケーリングはインターフェースのサイズに対して線形になります。あなたは@ Jarod42のコードを見てください。なぜなら、各インスタンスをたくさん減らすために素敵なtypedefを作ることを可能にする関数をテンプレート宣言に入れているからです。 – nissefors

0

と最後の部分を離れてラップすることができグループにまとめられたC関数のコレクションがあり、名前と署名は一貫したパターンに従います。 C++ラッパーにこれらの関数の1つを呼び出させたい場合は、その関数の名前をC++コードの中に明示する必要があります。これを達成するための選択は、ラッパーコードの適切な場所に文字通り名前を挿入するか、マクロを使用して名前を体系的に生成することです。あなたは両方の選択肢を拒否しました。

マクロを避けることを強くお勧めする場合は、(必要な関数を文字通り呼び出す)すべてのクラス定義のC++ソースを出力するコードジェネレータを作成することを検討できます。 Cライブラリが関数を変更したり追加したりするなど、何らかの理由で他の理由でクラスが再生成される可能性があります。

+0

私はまだ何かを拒否していません。私は代替案の重さを測っているし、人々がより良いアイデアを持っているのかどうかも疑問だ。 – celavek

+0

@celavekには、他のオプションはありません。あなたがすでに知っているもののバリエーションだけです。 –

関連する問題