私は抽象的なインターフェイスに対してコード化し、使用するコンパイル時にコンパイル時に選択できるように、同様の機能を持つ2つのサードパーティライブラリの共通インターフェイスを作成しようとしています。効率的で洗練されたインターフェイスの抽象化
オーバーヘッドを追加しないようにするには、この抽象的なインターフェイスが必要です。つまり、多態性は問題にはなりません。いずれにしても実際に実装されている実装が1つしかないので、これは必要ありません。だから私の最初の試みは、このように見えた:
AbstractInterface.h:
// Forward declarations of abstract types.
class TypeA;
class TypeB;
class TypeC;
TypeA *foo(TypeA *a, TypeB *b);
TypeB *bar(std::vector<TypeC*> &c);
TypeC *baz(TypeC *c, TypeA *c);
ImplementationOne.cpp:
class ActualTypeA {...};
using TypeA = ActualTypeA; // Error!
...
残念ながら、これはタイプAであることを言って、コンパイルエラーになりフォワード宣言はそれがクラスであるというよりも何も言わなかったとしても、異なる型を使って再定義されています。だから私が試した次の事は、このでした:ここ
class TypeA : public ActualTypeA {}; // No more error
...
TypeA *foo(TypeA *a, TypeB *b)
{
return actualFoo(a, b); // Error
}
、actualFoo()が自動的に*タイプAに変換することはできませんActualTypeA *を返します。 *私が誤ってタイプAにActualTypeA以外の何か*をキャストしないように
inline TypeA *A(ActualTypeA *a)
{
return reinterpret_cast<TypeA*>(a);
}
TypeA *foo(TypeA *a, TypeB *b)
{
return A(actualFoo(a, b));
}
理由私は(ヘルパー関数Aを使用しています)です。だから私のような何かにそれを書き換える必要があります。とにかく、私の実際のインターフェースは実装ごとに数万行のコードなので、私はこの解決策に興奮していません。そして、すべてのA()、B()、C()などは、読みにくくする。任意の実装側の変更を必要と回避このすべてについて移動する
inline std::vector<ActualTypeC*> &C(std::vector<TypeC*> &t)
{
return reinterpret_cast<std::vector<ActualTypeC*>&>(t);
}
TypeB *bar(std::vector<TypeC*> &c)
{
B(actualBar(C(c));
}
もう一つの方法は、::
AbstractInterface.h
さらに、バーの実装では、()いくつかの追加のブードゥー教が必要になります:
class ActualTypeA;
class ActualTypeB;
class ActualTypeC;
namespace ImplemetationOne
{
using TypeA = ActualTypeA;
using TypeB = ActualTypeB;
using TypeC = ActualTypeC;
}
class OtherActualTypeA;
class OtherActualTypeB;
class OtherActualTypeC;
namespace ImplemetationTwo
{
using TypeA = OtherActualTypeA;
using TypeB = OtherActualTypeB;
using TypeC = OtherActualTypeC;
}
// Pre-define IMPLEMENTATION as ImplementationOne or ImplementationTwo
using TypeA = IMPLEMENTATION::TypeA;
using TypeB = IMPLEMENTATION::TypeB;
using TypeC = IMPLEMENTATION::TypeC;
TypeA *foo(TypeA *a, TypeB *b);
TypeB *bar(std::vector<TypeC*> &c);
TypeC *baz(TypeC *c, TypeA *c);
これは、誰かが誤って実装固有を使用する可能性のある問題を持っています抽象的なものの代わりに型を使用します。また、このヘッダーを含むコンパイル単位ごとにIMPLEMENTATIONを定義する必要があり、一貫性が必要です。私はむしろ単にImplementationOne.cppかImplementationTwo.cppのどちらかをコンパイルしたいと思います。もう1つの欠点は、インプリメンテーション固有のタイプに実際に関心がない場合でも、ヘッダを変更する必要があることです。
これは非常に一般的な問題のように思われるので、よりエレガントで効率的なソリューションが見つからないのでしょうか?
あなたは継承が解決しようとしていた問題を解決するための広大な努力、英雄的な努力に向かいそうです。コンパイル時のインターフェースを探しているので、テンプレートを見る必要があります。 –
余分な機能を呼び出すことはオーバーヘッドであるため、問題の解決策にはなりません。一言で言えば、私はあなたが「コストはかかりません」と他の人が「確かにそれはコストがかかりません」というプロファイリングや確実性のないランダムなものを選んでいると考えています。 2つのインタフェースは、実際にメソッドと関数のためのメソッドであり、タイプ全体の型の関数と型ですか? – Yakk
実装を選択する情報が利用可能な場合は、タグディスパッチまたはSFINAEを使用してコンパイル時にインプリメンテーションを選択できます。コンパイル時の多型ですが、実行時の多形性を避けたいと思うのです。 – midor