2012-01-08 15 views
5

Piszę klasę, która ma unordered_set z własnego typu jako członka. Dlatego muszę napisać specjalizację dla hash<Foo>. Ta specjalizacja musi być zdefiniowana po zadeklarowaniu Foo. Ale wydaje mi się, że potrzebuję specjalizacji na hash<Foo> przed zdefiniowaniem członka unordered_set<Foo>. Przynajmniej nie kompiluje się i kończy się niepowodzeniem. Próbowałem zgłoszenia do przodu szablonu hasha, ale nie mogłem go również uruchomić.std :: unordered_set <Foo> jako członek klasy Foo

Odpowiedni fragment kodu jest:

class Foo { 
public: 
    int i; 
    std::unordered_set<Foo> dummy; 
    Peer(std::unordered_set<Foo>); 
}; 

namespace std { 
    template<> struct hash<Foo> 
    { 
     size_t operator()(const Foo& f) const 
     { 
      return hash<int>()(f.i); 
     } 
    }; 
} 

góry dzięki

Odpowiedz

8

Foo nie może mieć zmienną składową typu std::unordered_set<Foo>.

Nie można utworzyć instancji kontenera Biblioteki standardowej z niekompletnym typem. Zasadniczo, z kilkoma wyjątkami nieistotnymi tutaj, typ klasy nie jest kompletny, dopóki } nie zakończy swojej definicji.

Będziesz musiał przechowywać inny rodzaj w kontenerze (być może std::unique_ptr<Foo>) lub użyć biblioteki pojemników, która zapewnia pojemniki z możliwością niekompletnego typu (np. Boost ma taką bibliotekę kontenerów).

+0

Dzięki za szybką odpowiedź, wtedy spróbuję inaczej – devmapal

+0

Z jakiegoś powodu Clang pozwoli na to zachowanie. GCC prawidłowo identyfikuje problem. – vmrob

1

Można przenieść deklarację się trochę, aby go skompilować:

class Foo; 

namespace std { 
    template<> struct hash<Foo> { 
    size_t operator()(const Foo& f) const; 
    }; 
} 

class Foo { 
public: 
    int i; 
    std::unordered_set<Foo> dummy; 
    Foo(std::unordered_set<Foo>); 
}; 

namespace std { 
    size_t hash<Foo>::operator()(const Foo& f) const { 
    return hash<int>()(f.i); 
    } 
} 

Jak mówi James, choć deklaracja dummy jest zachowanie jest niezdefiniowane.

Będziesz także potrzebować porównania równości; najłatwiej dodać operator== do Foo.

Polecam również, aby konstruktor z Foo wziął argument za pomocą const-reference.

+0

Tak, kompiluje. Ale ponieważ tak naprawdę nie powinien się kompilować, ponieważ nie jest standardową kompilacją, nie powinienem używać tego w ten sposób, prawda? – devmapal

+0

@devmapal: Absolutnie w porządku, nie używaj tego. Właśnie napisałem na wypadek, gdybyś miał inne scenariusze szablonów w przyszłości, gdzie to może mieć zastosowanie. Zauważ, że problem polega tylko na tym, że standard mówi, że nie możesz tego * używać ze standardowymi szablonami bibliotek *. Możesz to zrobić za pomocą własnych szablonów, jeśli możesz udowodnić, że robi to dobrze. –

Powiązane problemy