2016-01-15 15 views
7

Więc czytałem this article about type erasure. Ale kod w tym artykule wydaje się częściowo błędne, na przykład:Co to jest wymazywanie typów w 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(); } 
}; 

następnie

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

Te błędy zniechęca mnie od czytania dalej w artykule.

W każdym razie; Czy ktoś może zadać pytanie, jaki typ wymazać w C++, za pomocą prostych przykładów?

Chciałem się dowiedzieć, jak działa std::function, ale nie mogłem się z tym pogodzić.

+0

związane/dupe: http://stackoverflow.com/questions/5450159/type-erasure-techniques – NathanOliver

+1

albo trzeba przejść '' lub użyć funkcji, która wywodzi 'T' i przechodzi' '. Tj., "Szablon MyAnimal * WrapAnimal (T const & t) {return new AnimalWrapper (t);}' i zamień 'nowy AnimalWrapper' na' WrapAnimal'. – Yakk

+0

@NathanOliver W tym pytaniu OP zna już podstawowe pojęcia wymazywania typu. –

Odpowiedz

10

Oto bardzo prosty przykład typu skasowaniem w akcji:

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

Jak widać, TypeErasedHolder może przechowywać obiekty dowolnego typu, a zniszczeniu je poprawnie. Ważne jest to, że nie nakłada żadnych ograniczeń na obsługiwane typy: (1): nie muszą one na przykład pochodzić ze wspólnej bazy.


(1) wyjątkiem jest ruchomy, oczywiście.

+0

Hm, dlaczego nie używasz '' && '' (odwołanie uniwersalne (?)) Do argumentu konstruktora '' TypeErasedHolder'' i '' std :: forward'', aby przekazać go do '' TypeKeeper' '? (próbując to zrozumieć, wydaje się, że zawsze zabierasz kopię, a następnie przesuwasz się z tej kopii zamiast przesuwać oryginalny obiekt). –

+1

@ JonasWielicki Zachowanie "bardzo prostego" aspektu przykładu. Korzystanie z odniesienia do przekazywania będzie również wymagać użycia 'std :: remove_reference' dla argumentu szablonu do' TypeKeeper', itp. – Angew

+0

Dzięki za wyjaśnienie! –