Modelli variadici e cast dinamico
-
27-10-2019 - |
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?
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]:
- ...] 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 '...'