2016-06-08 1 views
0

je le morceau de code suivant:motif de modèle Curieusement récurrent avec des modèles variadique (C++)

#include <iostream> 

template <typename Derived> 
struct Base { 
    void print() const { static_cast<const Derived*>(this)->print(); } 
}; 

struct Value : public Base<Value> { 
    int i; 
    void print() const { std::cout << "Value: " << i << std::endl; } 
    Value(int j) : i(j) {} 
}; 

void do_variadic_thing() {} 

template <typename Derived, typename... Args> 
void do_variadic_thing(const Base<Derived>& b, Args... args) { 
    std::cout << "Inside do_variadic_thing" << std::endl; 
    b.print(); 
    do_variadic_thing(args...); 
} 

template <typename Derived> 
void do_thing(const Base<Derived>& b) { 
    std::cout << "Inside do_thing" << std::endl; 
    b.print(); 
    do_variadic_thing(b, b, b); 
} 

int main(int argc, char** argv) { 
    do_thing(Value(1)); 
} 

Ce code utilise le motif de modèle Curieusement récurrent définir une classe polymorphique compilation d'une méthode appelée print. Ce que je veux faire est d'exécuter la méthode print d'une fonction avec un nombre variable d'arguments (do_variadic_thing). Le code prévu au-dessus compiles, mais produit une sortie étrange:

Inside do_thing 
Value: 1 
Inside do_variadic_thing 
Value: 1 
Inside do_variadic_thing 
Value: 4206337 
Inside do_variadic_thing 
Value: 4206337 

Je ne comprends pas pourquoi la valeur change imprimé après le deuxième appel récursif au sein do_variadic_thing. L'argument b est répliqué 3 fois; son type est également le même (c'est-à-dire Base<Value>). Il semble que d'une manière ou d'une autre, après le deuxième appel, les arguments ne se réfèrent plus à une mémoire valide.

Comment est-ce possible?

Répondre

3

passer par référence:

void do_variadic_thing(const Base<Derived>& b, const Args&... args) 
                 ^
                 here 
+0

Merci. J'ai manqué le fait que la référence 'b' était réellement passée comme _copy_ pour la partie variadique. – madmann91

1

Vous passez les deuxième/troisième instances par la valeur - considérez comment les copies sont construites.

+1

Notez également que 'Base ' n'est pas 'Value', il ne contient pas le champ' i' (ce problème est appelé "tranchage d'objet"). – kennytm

0

Le type de la variable est bBase<Value> const&, mais l'objet se réfère à est de type Value. Lorsque vous copiez b pour le répliquer à l'intérieur de do_thing, vous êtes en le découpant; c'est-à-dire, en copiant seulement la partie Base<Value>.