2016-07-25 9 views
-1

ich diese Klasse habenC++ das erste Argument Wert in Template-Parameter-Pack

class AssetManager 
{ 
private: 
    std::unordered_map<const std::type_info*, Asset*> assets; 

public: 
    AssetManager(); 
    virtual ~AssetManager(); 

    template <typename T, typename ...Args> 
    bool newAsset(Args... args) 
    { 
     //Get path 
     if(cached(path)) { return true; } 

     auto asset = new T{ std::forward<Args>(args)... }; 
     assets[&typeid(*asset)] = asset; 
     return *static_cast<T*>(assets[&typeid(T)]); 
    } 

    bool cached(const std::string& path) 
    { 
     for(auto asset : assets) { 
      if(asset.second->getPath() == path) { 
      return true; 
      } 
     } 

     return false; 
    } 
}; 

Das erste Argument eines jeden Vermögens immer std :: string Pfad. Ich versuche, diesen Wert zu erhalten und sehen, ob es bereits in der Liste geladen ist. Asset ist eine abstrakte Klasse.

class Asset 
{ 
private: 
    std::string path; 

public: 
    Asset(const std::string& path); 
    virtual ~Asset() = default; 
    virtual bool load() = 0; 
    std::string getPath(); 
}; 

Anlageklassen erben unterschiedliche Anzahl von Argumenten haben und als solche ich versuche, den Wert des ersten Arguments zu erfassen, weil es immer eine std :: string Pfad sein wird, wie Sie in der Asset-Klasse sehen können Konstrukteur.

+5

Bin ich völlig zu einfältig, wenn ich dir sage, nur ein std :: string Argument vor args zu deklarieren, da es obligatorisch ist? –

+1

Ja, mach das. Andernfalls können Sie nicht erzwingen, was die Leute im Paket weitergeben. Warum sollten Sie die Möglichkeit verpassen, es falsch zu machen? –

+4

Schlagen Sie 'bool newAsset (Args && ... args)' vor, um eine einwandfreie Weiterleitung zu unterstützen. Ohne das '&&' kopierst du immer deine Argumente. – aschepler

Antwort

5

Wenn Ihr erstes Argument immer ein std :: string ist, ist es sehr sinnvoll, es einfach so zu deklarieren. Zum einen löst es dieses Problem. Zum anderen sorgt es dafür, dass Anrufer nie falsch liegen können. Und wenn Sie es auch im Konstruktor von Asset benötigen, übergeben Sie es entweder separat an diesen Konstruktor oder deklarieren Sie es auch dort.

template <typename T, typename ...Args> 
bool newAsset(const std::string &path, Args&&... args) 
{ 
    //Get path 
    if(cached(path)) { return true; } 

    auto asset = new T{ path, std::forward<Args>(args)... }; 
    assets[&typeid(*asset)] = asset; 
    return *static_cast<T*>(assets[&typeid(T)]); 
} 

Ich frage mich auch über Ihre Verwendung von Typid; Sind Sie absolut sicher, dass es als Schlüssel in einer Karte richtig ist? Ich sehe keinen Operator <, und Operator == wird nicht garantiert, um konsistente Ergebnisse gemäß http://en.cppreference.com/w/cpp/language/typeid (unter 'Hinweise') zu geben. Es könnte besser sein, stattdessen typeid.hash_code() zu verwenden.

+0

Ich denke, ich bleibe bei dieser Lösung. Vielen Dank :) – vegeta

0
  • Make Pfad ein Pflichtparameter, jetzt können Sie sich darauf beziehen, wenn Sie Ihre cached Lookup
  • Übergeben Sie den Pfad und den Rest der Argumente zusammen zu Ihrem Asset Konstruktor

.

template <typename T, typename ...Args> 
bool newAsset(const std::string& path, Args&&... args) 
{ 
    if(cached(path)) { return true; } 

    auto asset = new T{ path, std::forward<Args>(args)... }; 
    assets[&typeid(*asset)] = asset; 
    return *static_cast<T*>(assets[&typeid(T)]); 
}