BREW API と intrusive_ptr の親和性

は最悪だと思うのです。
C での擬似的な継承関係は C++ の継承関係とは関係が無いので、型の変換が一切できないのです。

intrusive_ptr<IShell> shell;
intrusive_ptr<IBase> base;
shell = base; // 当然エラー
base = shell; // エラー
base = static_pointer_cast<IBase>(shell); // エラー
base = shell.get(); // エラー
base = static_cast<IBase*>(shell.get()); // エラー
base = reinterpret_cast<IBase*>(shell.get()); // ようやく OK

というかそもそも intrusive_ptr_add_ref と intrusive_ptr_release も IBase* に変換できないので、必要になった BREW API の数だけ全部定義してやる必要があります。

void intrusive_ptr_add_ref(IBase* obj)
{
    IBASE_AddRef(reinterpret_cast<IBase*>(obj));
}
void intrusive_ptr_release_ref(IBase* obj)
{
    IBASE_Release(reinterpret_cast<IBase*>(obj));
}
void intrusive_ptr_add_ref(IShell* obj)
{
    IBASE_AddRef(reinterpret_cast<IBase*>(obj));
}
void intrusive_ptr_release_ref(IShell* obj)
{
    IBASE_Release(reinterpret_cast<IBase*>(obj));
}

超めんどい。やってられない。


以下のように書けるのが理想です。

intrusive_ptr<IBase> base;
intrusive_ptr<IShell> shell;
intrusive_ptr<IDisplay> display;
base = display; // OK
shell = display; // エラー
shell = static_pointer_cast<IShell>(base); // OK
shell = static_pointer_cast<IShell>(display); // エラー

どれも C++ の継承関係があるなら全部当たり前なことなのですが、BREW API は C 互換なので仕方が無いのでしょうね……。


ということで、ゴリゴリと書いて頑張ってみました。
intrusive_ptr<> という汎用的なクラスで扱うのは諦めて brew_ptr<> という BREW 専用のクラスにしておいて、自前で BREW の継承関係を C++ の継承で定義したクラスを作って、BREW のクラスからその継承関係を調べるためのクラスを取得できるような traits を作ってやってます。
自前で継承関係を作ってるので、クラスを追加するのが面倒だったりとかするのですが、まあ強制キャストで押し通すよりはマシになったかなと。


以下実装

続きを読む