それ自体へのポインターからそれ自体を含むオブジェクトへのポインターを計算できるメンバー変数を持つことは可能ですか?
次のように API でラップされた外部呼び出しインターフェイスを用意しましょう。
template <typename Class, MethodId Id, typename Signature>
class MethodProxy;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodProxy<Class, Id, ReturnT ()(Arg1T) {
public:
ReturnT operator()(Class &invocant, Arg1T arg1);
};
0 から N までの他の数の引数についても同様です。外部側の各クラスでは、1 つの C++ クラスがいくつかのトレイトで宣言され、このテンプレートはそれらのトレイト (および引数の型のその他のトレイト) を使用して、外部メソッドを見つけて呼び出します。これは次のように使用できます。
Foo foo;
MethodProxy<Foo, barId, void ()(int)> bar;
bar(foo, 5);
今私がやりたいのはFoo
、次のように呼び出すことができるような方法で定義することです:
Foo foo;
foo.bar(5);
署名を何度も繰り返さずに。(明らかに、静的メンバーを作成し、呼び出しをメソッドにラップするのは簡単です)。実際、それはまだ簡単です。
template <typename Class, MethodId Id, typename Signature>
class MethodMember;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodMember<Class, Id, ReturnT ()(Arg1T) {
MethodProxy<Class, Id, Signature> method;
Class &owner;
public:
MethodMember(Class &owner) : owner(owner) {}
ReturnT operator()(Arg1T arg1) { return method(owner, arg1); }
};
ただし、それは、オブジェクトがそれ自体へのポインタの多くのコピーを含むことになることを意味します。this
したがって、これらのインスタンスが所有者ポインターといくつかの追加のテンプレート引数を計算できるようにする方法を探しています。
の方針に沿って考えていた
template <typename Class, size_t Offset, ...>
class Member {
Class *owner() {
return reinterpret_cast<Class *>(
reinterpret_cast<char *>(this) - Offset);
}
...
};
class Foo {
Member<Foo, offsetof(Foo, member), ...> member;
...
};
しかし、これは Foo がその時点で不完全な型であると不平を言っています。
はい、offsetof
「POD」タイプでのみ機能するはずですが、実際には非仮想メンバーで機能します。同様に、その引数に (ダミーの基本クラスを使用して) メンバーへのポインターを渡そうとしましたが、それも機能しません。
これが機能する場合は、含まれているクラスのメソッドに委譲する C# のようなプロパティを実装するためにも使用できることに注意してください。
上記のラッパー メソッドを boost.preprocessor で実行する方法は知っていますが、引数リストは奇妙な形式で指定する必要があります。テンプレートを介して一般的なラッパーを生成するマクロを作成する方法は知っていますが、それでは診断が不十分になる可能性があります。呼び出しが次のように見える場合も簡単ですfoo.bar()(5)
。しかし、いくつかの巧妙なトリックが可能かどうかを知りたいです (さらに、そのような巧妙なトリックのみがプロパティにも使用できる可能性があります)。
注: オフセットを割り当てる前に型を認識しておく必要があるため、メンバー型は、それへのメンバー ポインターまたはそのオフセットのいずれかで実際に特殊化することはできません。これは、型が必要なアラインメントに影響を与える可能性があるためです (明示的/部分的な特殊化を検討してください)。