3

変数階層 (以下の ObjGetter) から派生するクラス (以下の MyGizmo) のユーザーに、引数を取らないメンバー関数 (以下の check()) を明確に呼び出す単純で整然とした方法を提供しようとしています。引数を取る関数 (以下の tune() など) でこれを機能させることができますが、引数を取らない関数で機能させる方法が見つかりませんでした。

struct Base { };
struct ObjA : public Base { };
struct ObjB : public Base { };
struct ObjC : public Base { };

template <class ... Obj> struct ObjGetter;

template <class Obj, class ... Tail>
struct ObjGetter<Obj, Tail ...> : public ObjGetter<Tail ...>
{
  using ObjGetter<Tail ...>::tune;  // resolve ambiguous lookups for tune()

  void tune(Obj * obj) { } // no problem with this one, disambiguated by obj type

  Obj * check() const { return 0; } // problem with this one, no arg to disambiguate
};

template <> struct ObjGetter<> { // to terminate the recursion
  void tune(void);  // needed by the using statement above but should not be used, hence different syntax
};

struct MyGizmo : public ObjGetter<ObjA, ObjC> // variadic
{
  void testit() {
    ObjA * a = 0; ObjB *b = 0; ObjC *c = 0;

    a = ObjGetter<ObjA, ObjC>::check(); // too ugly!
    c = ObjGetter<ObjC>::check(); // too ugly!

    tune(a); // no problem
    //tune(b); // correct compile-time error: no matching function for call to ‘MyGizmo::tune(ObjB*&)’
    tune(c); // no problem

    // I would like a simple syntax like this:
    //a = check<ObjA>(); // should call ObjGetter<ObjA, ObjC>::check()
    //b = check<ObjB>(); // should give a compile-time error
    //c = check<ObjC>(); // should call ObjGetter<ObjC>::check()
  }
};

私は次のことを試しましたが、完全には満足していません:

まず、階層内で使用される単純にテンプレート化された 2 番目のクラスを使用して、醜い呼び出しを減らしてテンプレート引数を 1 つだけ持つことができます。次のような結果が得られます。

a = ObjGetterHelper<ObjA>::check(); // still ugly! MyGizmo user should not have to know about ObjGetterCore
c = ObjGetterHelper<ObjC>::check(); // too ugly!

Type2Type ヘルパーを使用して check() に引数を与えることができます。これは問題なく動作します。次のようになります。

a = check(Type2Type<ObjA>()); // pretty ugly too
c = check(Type2Type<ObjC>()); // pretty ugly too

マクロを使用できますが、そこに行きたくありません...

#define CHECK(X) check(Type2Type<X>())

テンプレートエイリアスが解決策を提供すると思いますが、まだサポートしていない g++ を使用しています。その間、他に何かありますか?どうもありがとう!

4

1 に答える 1

2

check<Type>型が可変長リストの先頭と一致しない場合、継承チェーンを委任するために、何らかの構造を持つメンバー関数テンプレートが必要です。

これは、SFINAE の典型的な問題です。

  template< class Obj2 >
  typename std::enable_if< std::is_same< Obj, Obj2 >::value, Obj * >::type
  check() const { return 0; } // perform work

  template< class Obj2 >
  typename std::enable_if< ! std::is_same< Obj, Obj2 >::value, Obj2 * >::type
  check() const { return base::template check< Obj2 >(); } // delegate

私の他の答えと同じように機能します。それはバロックの愚かさの例として残しておきます。

于 2010-08-17T21:48:47.570 に答える