Variadic шаблоны и динамическое приведение - PullRequest
7 голосов
/ 08 сентября 2011

У меня есть фрагмент кода 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));

Я просмотрел много статей о шаблонах с вариациями. Однако через пару часов я все еще не могу понять это.

Есть идеи?

Ответы [ 2 ]

10 голосов
/ 08 сентября 2011

Просто

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 и B) в одном расширении пакета (здесь dynamic_cast), при условии, что они имеют одинаковый размер; в противном случае, это тихая ошибка из-за SFINAE. От n3290, 14.5.3 / 5 шаблонов Variadic [temp.variadic]:

  1. [...] Шаблон расширения пакета должен называть один или несколько пакетов параметров которые не расширяются вложенным пакетом расширения; такие пакеты параметров называются нерасширенными пакетами параметров в шаблоне. Все Пакеты параметров, расширенные расширением пакета, должны иметь одинаковые количество аргументов указано. [...]

1 : Я не могу найти точную ссылку на то, разрешен ли здесь вычет или нет; GCC может даже вывести обе пачки, если я превращу CastAll в полиморфный функтор. Я немного сомневаюсь, если это вообще обязательное поведение, но, по крайней мере, вы, похоже, знаете, как в любом случае указывать необусловленный аргумент.

0 голосов
/ 08 сентября 2011

[ПРАВИТЬ] Переписано с нуля.Нечто подобное должно быть возможным, но у меня нет доступа к компилятору, который позволяет переменным шаблонным функциям , а не быть концом, поскольку это больше не требуется.Это не сработает, если вы не передадите хотя бы один параметр, но я не вижу в этом проблемы.

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: ошибка:ожидаемый ';'до '...' токена

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...