2012-01-08 2 views
5

Sto scrivendo una classe che ha un unordered_set del proprio tipo come membro. Quindi ho bisogno di scrivere una specializzazione per hash<Foo>. Questa specializzazione deve essere definita dopo che Foo è stato dichiarato. Ma mi sembra che ho già bisogno della specializzazione per hash<Foo> prima di definire il membro unordered_set<Foo>. Almeno non si compila e fallisce lì. Ho provato una dichiarazione in avanti del modello di hash ma non riuscivo a farlo funzionare neanche.std :: unordered_set <Foo> come membro della classe Foo

Il frammento di codice relativo è:

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); 
     } 
    }; 
} 

Grazie in anticipo

risposta

8

Foo non può avere una variabile membro di tipo std::unordered_set<Foo>.

Non è possibile creare un'istanza di un contenitore di libreria standard con un tipo incompleto. Fondamentalmente, con diverse eccezioni non rilevanti qui, un tipo di classe non è completo fino allo } che termina la sua definizione.

È necessario memorizzare un altro tipo nel contenitore (ad esempio std::unique_ptr<Foo>) oppure utilizzare una libreria contenitori che fornisce i contenitori con istanza con un tipo incompleto (ad es. Boost ha una libreria di tali contenitori).

+0

Grazie per la risposta veloce, quindi proverò in modo diverso – devmapal

+0

Per qualche motivo, Clang consentirà questo comportamento. GCC identifica correttamente un problema. – vmrob

1

È possibile spostare la dichiarazione un po 'intorno per renderlo compilare:

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); 
    } 
} 

Come dice James, però, la dichiarazione di dummy è è un comportamento indefinito.

Avrete anche bisogno di un confronto di uguaglianza; più semplice aggiungere un operator== a Foo.

Si consiglia inoltre di fare in modo che il costruttore di Foo prenda l'argomento per riferimento const.

+0

Sì, lo compila. Ma dato che in realtà non dovrebbe essere compilato perché non è compilatore standard, non dovrei usarlo in questo modo, giusto? – devmapal

+0

@devmapal: assolutamente giusto, non usare questo. Ho appena inserito nel caso in cui in futuro vi siano altri scenari di modelli in cui ciò potrebbe essere applicato. Nota che il problema è solo che lo standard dice che non devi farlo * con i modelli di libreria standard *. Sei libero di farlo con i tuoi modelli se riesci a dimostrare che fa la cosa giusta. –