6

次のような C++ コードがあります。

template <typename ...A> 
struct CastAll{
  template <typename ...B>
  void cast_all(void(*fun)(B...), A...as){
    //...
  }
};

私がやりたいのは、引数のそれぞれを B のそれぞれの型に動的キャストし、「キャストされた」引数で指定された関数 fun を呼び出すような方法で cast_all を実装することです。

たとえば、次のようになります。

struct A{};

struct B : public A{};

void foo(B *b1, B *b2){
  //... does something with b1 and b2
}

int main(){

  A *a1 = new B();
  A *a2 = new B();

  CastAll<B*, B*> cast; //used to cast each A* to B*
  cast.cast_all<B*, B*>(foo, a1, a2);
}

cast_all は次のように展開する必要があります: foo(dynamic_cast(a1), dynamic_cast(a2));

可変個引数テンプレートに関する多くの記事を見てきました。しかし、数時間後、私はまだそれを理解することができません.

何か案は?

4

2 に答える 2

9

単に

template <typename ...A> 
struct CastAll{
    template <typename ...B>
    void cast_all(void(*fun)(B...), A...as){
        fun(dynamic_cast<B>(as)...);
    }
};

動作するはずであり、GCC の私のコピーで動作します。ただし、サンプル コードにいくつかの変更が必要です。ポリモーフィックにする必要がありますA(これにより、Bポリモーフィックになります)dynamic_cast可能になります (サンプル コードで慣例として、仮想のデフォルト デストラクタを追加しました)。おそらく次のように使用するつもりでしたCastAll

CastAll<A*, A*> cast;
cast.cast_all(foo, &a1, &a2);

つまり、渡す引数cast_allはポインタであり、ボディの内部にAダウンキャストされます。Bさらに、いくつかのテンプレート パラメータが推定されます1

これが機能するのは、サイズが同じであれば、1 つのパック展開 (ここでは) で複数のパラメーター パック (ここではAと) を使用できるためです。それ以外の場合は、SFINAE によるサイレント エラーです。n3290 から、14.5.3/5 Variadic テンプレート [temp.variadic]:Bdynamic_cast

  1. [...] パック展開のパターンは、ネストされたパック展開によって展開されない 1 つ以上のパラメーター パックに名前を付けます。このようなパラメーター パックは、パターン内で展開されていないパラメーター パックと呼ばれます。パック展開によって展開されるすべてのパラメーター パックには、同じ数の引数が指定されている必要があります。[...]

1 : ここで演繹が許可されているかどうかについての決定的な参照が見つかりません。CastAllポリモーフィック ファンクターに変換すると、GCC は両方のパックを推測することさえできます。これが義務付けられた動作であるかどうかはやや疑わしいですが、少なくとも推定されていない引数を指定する方法を知っているようです。

于 2011-09-08T03:14:22.917 に答える
0

【追記】一から書き直しました。このようなことは可能であるはずですが、可変個引数のテンプレート関数が最後にならないようにするコンパイラーへのアクセスはありません。少なくとも 1 つのパラメーターを渡さないと失敗しますが、それが問題だとは思いませんでした。

template<typename...BL>
struct Recast {
    template <typename B, typename ...BR>
    struct Inner {
        template <typename A, typename ...AR>
        static void cast_all(void(*fun)(BL...,B,BR...), BL... al, A a, AR... ar) {
            Recast<BL..., B>::template Inner<BR...>::cast_all<AR...>(fun, al..., dynamic_cast<B>(a), ar..);
        }
    };
    template <typename B>
    struct Inner<B> {
        template <typename A>
        static void cast_all(void(*fun)(BL...,B), BL... al, A a) {
            fun(al..., dynamic_cast<B>(a));
        }
    };
};

template <typename ...BR>  //note I switched these
struct CastAll{
    template <typename ...AR>  //note I switched these
    static void cast_all(void(*fun)(BR...), AR...ar){
      Recast<>::template Inner<BR...>::cast_all(fun, ar...);
    }
};

struct A{};

struct B : public A{};

void foo(B *b1, B *b2){
  //... does something with b1 and b2
}

int main(){

  A *a1 = new B();
  A *a2 = new B();

  CastAll<B*, B*>::cast_all(foo, a1, a2);
}

ideone.com によって報告されたように、まだ把握できないエラーがあることを認めます。

prog.cpp: 静的メンバー関数内 'static void Recast::Inner::cast_all(void (*)(BL ..., B, BR ...), BL ..., A, AR ...)' :
prog.cpp:7:39: エラー: '...' トークンの前にプライマリ式が
必要です prog.cpp:7:39: エラー: ';' が必要です 「...」トークンの前

于 2011-09-07T22:23:17.077 に答える