Domanda

Ho un pezzo di codice C ++ come segue:

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

Quello che mi piacerebbe fare è implementare Cast_all in modo tale da far esplodere dinamico ciascuno dei suoi argomenti al rispettivo tipo in B e quindi chiama la funzione data divertente con gli argomenti "lanciati".

Ad esempio, in:

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 dovrebbe espandersi in qualcosa come: Foo (Dynamic_cast (A1), Dynamic_Cast (A2));

Ho esaminato molti articoli su modelli variadici. Tuttavia, dopo un paio d'ore, non sono ancora in grado di capirlo.

Qualche idea?

È stato utile?

Soluzione

Semplicemente

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

Dovrebbe funzionare e fa con la mia copia di GCC. Sono necessarie alcune modifiche al tuo codice di esempio: A dovrebbe essere polimorfico (che farà B polimorfico a sua volta) in modo che dynamic_cast Sii possibile (ho aggiunto un distruttore virtuale e predefinito come è consuetudine nel mio codice di esempio); E probabilmente hai intenzione di usare CastAll come:

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

Vale a dire, l'argomento a cui passi cast_all sono suggerimenti per A che vengono quindi abbattuti a B All'interno del corpo. Inoltre, alcuni dei parametri del modello vengono dedotti1.

Funziona perché ti è permesso utilizzare diversi pacchetti di parametri (qui, A e B) in un'espansione di un pacchetto (qui, il dynamic_cast), a condizione che abbiano le stesse dimensioni; Altrimenti, è un errore silenzioso dovuto a Sfinae. Da N3290, 14.5.3/5 Modelli variadici [temp.variadic]:

  1. ...] Il modello di espansione di un pacchetto deve nominare uno o più pacchetti di parametri che non sono ampliati da un'espansione del pacchetto nidificato; Tali pacchetti di parametri sono chiamati pacchetti di parametri non pagati nel modello. Tutti i pacchetti di parametri ampliati da un'espansione di un pacchetto devono avere lo stesso numero di argomenti specificati. [...

1: Non riesco a trovare un riferimento definitivo sul fatto che la detrazione sia consentita o meno; GCC è persino in grado di dedurre entrambi i pacchetti se giro CastAll in un funtore polimorfico. Sono un po 'dubbio se questo è un comportamento obbligatorio, ma almeno sembri sapere come specificare comunque argomenti non deduti.

Altri suggerimenti

Modifica] riscritto da zero. Qualcosa del genere dovrebbe essere possibile, ma non ho ACECSS a un compilatore che consente alle funzioni del modello variadico non Sii una fine, poiché ciò non è più richiesto. Questo fallisce se non passi almeno un parametro, ma non l'ho visto come un problema.

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);
}

Riconosco che ci sono ancora errori che non riesco a capire come riportato da ideone.com

Prog.cpp: nella funzione membro statico 'statico vuoto recast :: interno :: cast_all (void (*) (bl ..., b, br ...), bl ..., a, ar ...)' :
Prog.CPP: 7: 39: Errore: token "...
Prog.cpp: 7: 39: Errore: previsto ';' prima del token '...'

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top