2016-01-15 22 views
7

Quindi stavo leggendo this article about type erasure. Ma il codice in tale articolo sembra parzialmente errata, ad esempio:Che cos'è la cancellazione di tipo 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(); } 
}; 

seguito da

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

Questi errori mi scoraggiati dal leggere oltre in questo articolo.

In ogni caso; qualcuno può insegnare quale tipo di cancellazione in C++ significa, con semplici esempi?

Volevo saperne di più per capire come funziona std::function, ma non riuscivo a capirlo.

+0

correlati/vittima: http://stackoverflow.com/questions/5450159/type-erasure-techniques – NathanOliver

+1

Si sia necessario passare '' , o utilizzare una funzione che deduce 'T' e passa' '. Cioè, 'modello MyAnimal * WrapAnimal (T const & t) {restituisce nuovo AnimalWrapper (t);}', e sostituisce 'new AnimalWrapper' con' WrapAnimal'. – Yakk

+0

@NathanOliver In questa domanda, OP conosce già i concetti di base della cancellazione dei tipi. –

risposta

10

Ecco un esempio molto semplice di tipo cancellazione in azione:

// 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]

Come si può vedere, TypeErasedHolder può memorizzare oggetti di un tipo arbitrario, e distruggere in modo corretto. Il punto importante è che non impone alcuna restrizione sui tipi supportati (1): ad esempio, non devono derivare da una base comune.


(1) Tranne essendo mobile, naturalmente.

+0

Hm, perché non stai usando '' && '' (riferimento universale (?)) Per l'argomento costruttore di '' TypeErasedHolder'' e '' std :: forward'' per passarlo al '' TypeKeeper'? '? (cercando di capire qui, sembra che tu stia sempre prendendo una copia e poi spostandoti da quella copia invece di spostare l'oggetto originale) –

+1

@JonasWielicki Per mantenere l'aspetto "molto semplice" dell'esempio. L'utilizzo di un riferimento di inoltro richiederebbe anche l'uso di 'std :: remove_reference' per l'argomento del template su' TypeKeeper', ecc. – Angew

+0

Grazie per il chiarimento! –