2016-01-15 12 views
7

So las ich this article about type erasure. Aber der Code in diesem Artikel scheint teilweise falsch, zum Beispiel:Was ist Typ löschen in C++?

template <typename T> 
class AnimalWrapper : public MyAnimal 
{ 
    const T &m_animal; 

public: 
    AnimalWrapper(const T &animal) 
     : m_animal(animal) 
    { } 

    const char *see() const { return m_animal.see(); } 
    const char *say() const { return m_animal.say(); } 
}; 

gefolgt von

void pullTheString() 
{ 
    MyAnimal *animals[] = 
    { 
     new AnimalWrapper(Cow()), /* oO , isn't template argument missing? */ 
     .... 
    }; 
} 

Diese Fehler entmutigten mich vom Lesen weiter in dem Artikel.

Wie auch immer; Kann mir bitte jemand beibringen, welche Art von Löschen in C++ bedeutet, mit einfachen Beispielen?

Ich wollte darüber lernen, um zu verstehen, wie std::function funktioniert, konnte aber nicht meinen Kopf herumkommen.

+0

verwandt/Betrogene: http://stackoverflow.com/questions/5450159/type-erasure-techniques – NathanOliver

+1

Sie müssen entweder '' passieren, oder eine Funktion verwenden, die 'T' folgert und übergibt' '. Dh, 'template MyAnimal * WrapAnimal (T const & t) {gebe den neuen AnimalWrapper (t);}' zurück und ersetze 'new AnimalWrapper' durch' WrapAnimal'. – Yakk

+0

@NathanOliver In dieser Frage kennt OP bereits grundlegende Konzepte des Typs Löschen. –

Antwort

10

Hier ist ein sehr einfaches Beispiel für Typ Löschung in Aktion:

// Type erasure side of things 

class TypeErasedHolder 
{ 
    struct TypeKeeperBase 
    { 
    virtual ~TypeKeeperBase() {} 
    }; 

    template <class ErasedType> 
    struct TypeKeeper : TypeKeeperBase 
    { 
    ErasedType storedObject; 

    TypeKeeper(ErasedType&& object) : storedObject(std::move(object)) {} 
    }; 

    std::unique_ptr<TypeKeeperBase> held; 

public: 
    template <class ErasedType> 
    TypeErasedHolder(ErasedType objectToStore) : held(new TypeKeeper<ErasedType>(std::move(objectToStore))) 
    {} 
}; 

// Client code side of things 

struct A 
{ 
    ~A() { std::cout << "Destroyed an A\n"; } 
}; 

struct B 
{ 
    ~B() { std::cout << "Destroyed a B\n"; } 
}; 

int main() 
{ 
    TypeErasedHolder holders[] = { A(), A(), B(), A() }; 
} 

[Live example]

Wie Sie sehen können, TypeErasedHolder können Objekte eines beliebigen Typs speichern, und sie richtig zerstören. Der wichtige Punkt ist, dass er den unterstützten Typen keine Beschränkungen auferlegt (1): Sie müssen zum Beispiel nicht von einer gemeinsamen Basis ableiten.


(1) Außer bewegbar ist, selbstverständlich.

+0

Hm, warum benutzen Sie '' && '' (Universalreferenz (?)) Nicht für das Konstruktorargument '' TypeErasedHolder'' und '' std :: forward'', um es an '' TypeKeeper' 'weiterzuleiten '? (Versuch, hier zu verstehen, es scheint, dass du immer eine Kopie nimmst und dann von dieser Kopie bewegst, anstatt das ursprüngliche Objekt zu bewegen) –

+1

@JonasWielicki Um den "sehr einfachen" Aspekt des Beispiels zu behalten. Die Verwendung einer Forwarding-Referenz würde auch die Verwendung von 'std :: remove_reference' für das Template-Argument zu' TypeKeeper' usw. erfordern. – Angew

+0

Danke für die Klarstellung! –