2017-03-22 2 views
1

Für eine innere Vorlagenstruktur einer Vorlagenklasse möchte ich einen variablen Vorlagenkonstruktor haben. Leider reicht der Konstruktor (siehe erster Konstruktor unten) nicht aus: Wenn ich nur diesen Konstruktor verwende, erhalte ich C2260-Compilerfehler, die angeben, dass die Konstruktorfunktion nicht 3, 4 oder 5 Argumente benötigt. Auf der anderen Seite funktioniert alles, indem Sie drei weitere Konstruktoren hinzufügen (siehe die restlichen Konstruktoren unten), wie beabsichtigt.Variadischer Vorlagenkonstruktor akzeptiert keine X-Argumente

template< typename KeyT, typename ResourceT > 
class ResourcePool { 

    ... 

    template< typename DerivedResourceT > 
    struct ResourcePoolEntry final : public DerivedResourceT { 

     template< typename... ConstructorArgsT > 
     ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ConstructorArgsT... args) 
      : DerivedResourceT(args...), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 

     ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ID3D11Device2 &x) 
      : DerivedResourceT(x), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 

     ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ID3D11Device2 &x, const wstring &y) 
      : DerivedResourceT(x,y), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 

     template < typename VertexT > 
     ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ID3D11Device2 &x, const wstring &y, const MeshDescriptor<VertexT> &z) 
      : DerivedResourceT(x, y, z), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 

      ... 
    } 
} 

ist Der Konstruktor wie folgt aufgerufen:

template< typename KeyT, typename ResourceT > 
template< typename... ConstructorArgsT > 
std::shared_ptr<ResourceT> ResourcePool< KeyT, ResourceT >::GetResource(KeyT key, ConstructorArgsT... args) { 
    return GetDerivedResource< ResourceT, ConstructorArgsT... >(key, args...); 
} 

template< typename KeyT, typename ResourceT > 
template< typename DerivedResourceT, typename... ConstructorArgsT > 
std::shared_ptr<ResourceT> ResourcePool< KeyT, ResourceT >::GetDerivedResource(KeyT key, ConstructorArgsT... args) { 
    ... 
    auto new_resource = std::shared_ptr< ResourcePoolEntry<DerivedResourceT> >(
     new ResourcePoolEntry<DerivedResourceT>(*this, key, args...)); 
    ... 
} 

Für eine primitive wie ein bool als variadische Argument, alles funktioniert.

Severity Code Description Project File Line Suppression State 
Error C2660  'mage::ResourcePool<std::wstring,mage::VertexShader>::ResourcePoolEntry<DerivedResourceT>::ResourcePoolEntry': function does not take 3 arguments MAGE c:\users\matthias\documents\visual studio 2015\projects\mage\mage\mage\src\resource\resource_pool.tpp 37 

Wo die Leitung 37 an den Konstruktor Anruf entspricht (new ResourcePoolEntry<DerivedResourceT>(*this, key, args...)); im Beispiel oben)

Was mache ich falsch? (Compiler MSVC++ 14.0)

Minimal Beispiel:

#include <memory> 
#include <map> 

template < typename T > 
using SharedPtr = std::shared_ptr<T>; 

template < typename T > 
using WeakPtr = std::weak_ptr<T>; 

template< typename KeyT, typename ResourceT > 
using ResourceMap = std::map< KeyT, WeakPtr<ResourceT> >; 

template< typename KeyT, typename ResourceT > 
class ResourcePool { 

public: 

    template< typename... ConstructorArgsT > 
    SharedPtr<ResourceT> GetResource(KeyT key, ConstructorArgsT... args); 
    template< typename DerivedResourceT, typename... ConstructorArgsT > 
    SharedPtr<ResourceT> GetDerivedResource(KeyT key, ConstructorArgsT... args); 

private: 

    ResourceMap< KeyT, ResourceT > m_resource_map; 

    template< typename DerivedResourceT > 
    struct ResourcePoolEntry final : public DerivedResourceT { 

    public: 

     template< typename... ConstructorArgsT > 
     ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ConstructorArgsT... args) 
      : DerivedResourceT(args...), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 
    private: 

     ResourcePool< KeyT, ResourceT > &m_resource_pool; 
     KeyT m_resource_key; 
    }; 
}; 

template< typename KeyT, typename ResourceT > 
template< typename... ConstructorArgsT > 
SharedPtr<ResourceT> ResourcePool< KeyT, ResourceT >::GetResource(KeyT key, ConstructorArgsT... args) { 
    return GetDerivedResource< ResourceT, ConstructorArgsT... >(key, args...); 
} 

template< typename KeyT, typename ResourceT > 
template< typename DerivedResourceT, typename... ConstructorArgsT > 
SharedPtr<ResourceT> ResourcePool< KeyT, ResourceT >::GetDerivedResource(KeyT key, ConstructorArgsT... args) { 
    auto it = m_resource_map.find(key); 
    if (it != m_resource_map.end()) { 
     auto resource = it->second.lock(); 
     if (resource) { 
      return resource; 
     } 
     else { 
      m_resource_map.erase(it); 
     } 
    } 

    auto new_resource = SharedPtr< ResourcePoolEntry<DerivedResourceT> >(
     new ResourcePoolEntry<DerivedResourceT>(*this, key, args...)); 
    m_resource_map[key] = new_resource; 
    return new_resource; 
} 

#include <d3d11_2.h> 

struct A { 
}; 
struct B : public A { 
    B(ID3D11Device &device) : A() {} 
}; 


const D3D_FEATURE_LEVEL g_feature_levels[] = { 
    D3D_FEATURE_LEVEL_11_1, 
    D3D_FEATURE_LEVEL_11_0 
}; 

int main() { 

    ID3D11Device *device; 
    ID3D11DeviceContext *device_context; 
    D3D_FEATURE_LEVEL feature_level; 
    D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, 
     g_feature_levels, _countof(g_feature_levels), D3D11_SDK_VERSION, 
     &device, &feature_level, &device_context 
    ); 

    ResourcePool< char, A > *pool = new ResourcePool< char, A >(); 
    //pool->template GetResource< int & >('a'); 
    pool->template GetDerivedResource< B, ID3D11Device & >('b', *device); 
} 

Fehler:

Severity Code Description Line Suppression State 
Error C2661 'ResourcePool<char,A>::ResourcePoolEntry<DerivedResourceT>::ResourcePoolEntry': no overloaded function takes 3 arguments 66 
+1

Liefern tatsächlichen Fehlertext. In tatsächlichen Zeilen. Stellen Sie idealerweise ein [MCVE] bereit, das den Fehler generiert. Möglicherweise müssen Sie Ihren Code ändern, um unwichtige Inhalte zu entfernen. Es ist sehr schwierig herauszufinden, ob Sie wichtige Dinge in Ihren "Details entfernen" beseitigt haben, und es wird zu einem Schmerz, Ihre Gedanken zu lesen. Ich werde bemerken, dass Ihr Variantkern die Dinge * nach Wert * nimmt, während Ihre Manuellen sie durch eine Mischung aus Referenz- und Konstantenbezug nehmen. – Yakk

+0

@Yakk Nimmt mein variadic ctor nicht alles auf, wie ich es passiere? – Matthias

+1

Es dauert Dinge von Wert. Dies könnte Probleme verursachen. Ich kann es nicht sagen, weil Sie die tatsächlichen Build-Fehler nicht erstellt haben und ich nicht jeden Typ kenne, mit dem Sie arbeiten. Nochmal [MCVE], und tatsächliche Fehler, oder deine Frage ist schlecht. – Yakk

Antwort

2

Eine Sache zu beachten (die möglicherweise nicht die letzte Ursache des Problems sein) ist, dass Sie tun nicht ganz das Richtige mit Ihrer Vorlage Parameterweiterleitung. Zum Beispiel, in dem Fall, in dem Sie einen ID3D11Device2 übergeben, erwartet Ihr DerivedResourceT Konstruktor wahrscheinlich (nach der Unterschrift Ihrer nicht-variadischen Konstruktoren zu urteilen) eine Referenz - aber aufgrund der Art und Weise, wie die Vorlagendeduktion funktioniert, wird sie stattdessen eine Kopie erhalten (wenn in der Tat ist das sogar zulässig - wenn es nicht kompiliert würde.

Um dies zu korrigieren, müssen Sie die Standard-Weiterleitung Rezept verwenden, die die korrekte l- oder r-valueness eines übergebenen Parameter weitergegeben werden können, was richtig Forwarding Referenzen enthält: In

template< typename... ConstructorArgsT > 
ResourcePoolEntry(ResourcePool< KeyT, ResourceT > &resource_pool, 
      KeyT resource_key, ConstructorArgsT&&... args) 
      : DerivedResourceT(std::forward<ConstructorArgsT>(args)...), m_resource_pool(resource_pool), m_resource_key(resource_key) {} 

Beachten Sie die oben genannten && in den Parametertyp args... und std::forward Aufruf.

+0

Dies scheint die Lösung zu sein, aber es sieht wie Chinesisch aus. Niemals Referenz-zu-Referenz && vorher verwendet. Und für die Zwischenaufrufe sollte GetResource -> GetDerivedResource && nicht verwendet werden? – Matthias

+1

Ja, Sie sollten - das perfekte Weiterleitungsrezept sollte immer beim Weiterleiten von Vorlagenparametern verwendet werden, die l-Werte oder r-Werte sein können und Sie nicht im Voraus wissen. [Hier] (http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html) ist ein Link, der r-Wert-Referenzen etwas erklärt (die '&&' Syntax) und [hier] (http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/) ist eine, die perfekte Weiterleitung erklärt – Smeeheey

+0

Danke für die Referenzen. Es macht Sinn (obwohl primitive Typen als Referenz entlang der gesamten Kette übergeben werden). – Matthias

Verwandte Themen