2016-06-23 9 views
2

Ich habe einen Speicherpool, der wie so aussieht:Wie erstelle ich einen Speicherpool mit einer beliebigen Anzahl von Containern?

template<typename TreeType> 
class LeafMemoryPool 
{ 
public: 
    void stealNodes(TreeType& tree); 
    Leaf* getNode(); 
private: 
    std::vector<Leaf*> mLeafs; 
} 

In meinem Programm Ich habe verschiedene TreeType s, wie FloatTree und Vec3Tree, und ich erstelle einen Speicherpool für jede Baumart. Allerdings ist es etwas nervig, diese zu übergeben, und ich würde einen einzelnen Speicherpool bevorzugen, der alle verschiedenen Typen behandelt. Außerdem muss ich in Zukunft möglicherweise weitere Typen hinzufügen, und ich möchte, dass es so dynamisch wie möglich ist. Könnte das mit variablen Vorlagen gemacht werden? Ich habe sie noch nie zuvor benutzt, und ich weiß nicht, ob sie dafür verwendet werden könnten.

Das Szenario I denk könnte als

template<typename... TreeTypes> 
class MemoryPool 
{ 
public: 
    // The template is only valid if the same type was declared 
    // in TreeTypes above 
    template<typename TreeType> 
    void stealNodes(TreeType& tree) 
    { 
     // Somehow need to access the right std::vector that 
     // stores TreeType::Leaf. This function will be called 
     // a lot, and needs to be determined at compile time 
     // for it to be useful. 
    } 

    template<typename TreeType> 
    typename TreeType::Leaf* getNode(); 
private: 
    // One for each TreeType in TreeTypes. 
    // The leaf type can be deduced by 
    // typename TreeType::Leaf 
    std::vector<LeafArg1*> mLeafsForArg1; 
    std::vector<LeafArg2*> mLeafsForArg2; 
    ... 
} 

Alles oben in Pseudo-Code geschrieben werden soll bei der Kompilierung festgelegt werden können. Kann ich das mit einigen C++ - Vorlagen lösen?

+0

std :: tuple wird es tun –

+0

So etwas wie 'template mit MemoryPools = std :: tuple ...>;'. – Jarod42

Antwort

3

Ja, das ist möglich. Ich werde Ihnen eine Lösung für eine vereinfachte Version Ihrer Klasse geben. Sie sollten diese Lösung für Ihre Klasse trivial anpassen können. Getestet mit gcc 6.1.1.

#include <vector> 

class A {}; 
class B {}; 
class C {}; 

template<typename ...Args> class pool; 

template<typename firstArg, typename ...Args> 
class pool<firstArg, Args...> : public pool<Args...> { 

public: 

    using pool<Args...>::stealNodes; 

    void stealNodes(firstArg &tree) 
    { 
    } 

private: 
    std::vector<firstArg *> leafs; 

}; 

template<> class pool<> { 

public: 

    void stealNodes(); // Undefined 
}; 


void foo() 
{ 
    pool<A, B, C> pool; 

    A a; 
    B b; 
    C c; 

    pool.stealNodes(a); 
    pool.stealNodes(b); 
    pool.stealNodes(c); 
} 
+0

Ich habe das jetzt ein paar Mal gelesen, aber ich bin mir immer noch nicht ganz sicher, was passiert. Was ist der Zweck der Unterklassenbildung? Und wie werden 'pool.stealNodes (a)' richtig zu dem "richtigen" 'std :: vector' bestimmt? – pingul

+1

@pingul Operator überladen. Sam, 'getNode' ist ein bisschen knifflig, du solltest es vielleicht einbinden. Vielleicht ein am meisten abgeleiteter 'pool ' Helfer, benenne deinen Typ in 'pool_impl' um und gebe' pool 'eine' Vorlage typename T :: Leaf * getNode() {return getNode (tag ); } '? Wobei 'pool_impl ' implementiert 'getNode (tag )'? – Yakk

+1

Oh, und um es aufzuräumen, würde ich die Vererbung von der Implementierung trennen. Wie 'struct simple_pool ' (mit der Funktion vector und stealNodes etc) und 'struct pool : simple_pool , pool {mit simple_pool :: stealNodes; Verwendung von Pool :: stealNodes; 'einfach weil die Fehlermeldungen in den meisten Compilern einfacher zu lesen sind. – Yakk

1
#include <tuple> 
#include <vector> 
#include <string> 

template<typename... TreeTypes> 
class MemoryPool 
{ 
public: 
    // The template is only valid if the same type was declared 
    // in TreeTypes above 
    template<typename TreeType> 
    void stealNodes(TreeType& tree) 
    { 
     // Somehow need to access the right std::vector that 
     // stores TreeType::Leaf. This function will be called 
     // a lot, and needs to be determined at compile time 
     // for it to be useful. 
     using leaf_type = typename TreeType::Leaf; 
     using vec_type = std::vector<leaf_type>; 
     auto& pool = std::get<vec_type>(_leaves); 
    } 

    template<typename TreeType> 
    typename TreeType::Leaf* getNode() 
    { 
     using leaf_type = typename TreeType::Leaf; 
     using vec_type = std::vector<leaf_type>; 
     auto& pool = std::get<vec_type>(_leaves); 

     // pool is now a reference to your vector 
    } 
private: 
    // One for each TreeType in TreeTypes. 
    // The leaf type can be deduced by 
    // typename TreeType::Leaf 

    std::tuple< std::vector<typename TreeTypes::Leaf> ... > _leaves; 
}; 
+0

Zwei Fragen: (1) Wird 'auto & pool' zur Kompilierzeit gebunden, oder wird eine Laufzeitsuche durchgeführt? (2) Wird es (speichertechnisch) ein Problem geben, wenn dynamische Objekte in einem 'std :: tuple' gespeichert werden? – pingul

+2

1) Kompilierzeit, 2) keine. –

+0

Gute Antwort, aber @ Sams Lösung macht 'stealNodes' zu einer Nicht-Template-Funktion, die bessere Fehlermeldungen liefert und abgeleitete' TreeType's besser behandelt. – Yakk