6

我有一段 C++ 代码如下:

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

我想做的是以这样的方式实现 cast_all ,它将每个参数动态转换为 B 中的相应类型,然后使用“转换”参数调用给定的函数 fun 。

例如,在:

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

这是有效的,因为您可以在一个包扩展(此处为)中使用多个参数包(此处A和) ,前提是它们具有相同的大小;否则,由于 SFINAE,这是一个静默错误。从 n3290,14.5.3/5 可变参数模板 [temp.variadic]:Bdynamic_cast

  1. [...] 包扩展的模式应命名一个或多个不通过嵌套包扩展扩展的参数包;此类参数包在模式中称为未扩展参数包。由包扩展扩展的所有参数包应具有相同数量的指定参数。[...]

1:我找不到关于这里是否允许扣除的明确参考;CastAll如果我变成多态函子,GCC 甚至可以推导出这两个包。如果这是强制行为,我有点怀疑,但至少你似乎知道如何指定非推导论点。

于 2011-09-08T03:14:22.917 回答
0

[编辑] 从头开始​​重写。这样的事情应该是可能的,但是我没有对允许可变参数模板函数不是终点的编译器的访问权,因为这不再需要。如果您不传递至少一个参数,这确实会失败,但我不认为这是一个问题。

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 回答