Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::unordered_set<Foo> as member of class Foo

I'm writing a class that has an unordered_set of its own type as a member. Therefore I need to write a specialization for hash<Foo>. This specialization needs to be defined after Foo is declared. But it seems to me as if I already need the specialization for hash<Foo> before defining the member unordered_set<Foo>. At least it doesn't compile and fails there. I tried a forward declaration of the hash template but couldn't get it working thereby either.

The relevant code snippet is:

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

Thanks in advance

like image 648
devmapal Avatar asked Jan 08 '12 22:01

devmapal


2 Answers

Foo cannot have a member variable of type std::unordered_set<Foo>.

You cannot instantiate a Standard Library container with an incomplete type. Basically, with several exceptions not relevant here, a class type is not complete until the } that terminates its definition.

You'll either need to store some other type in the container (perhaps std::unique_ptr<Foo>), or use a containers library that provides containers instantiable with an incomplete type (e.g., Boost has such a containers library).

like image 118
James McNellis Avatar answered Sep 24 '22 21:09

James McNellis


You can move the declaration around a bit to make it compile:

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

As James says, though, the declaration of dummy is is undefined behaviour.

You will also need an equality comparison; easiest to add an operator== to Foo.

I would also recommend making the constructor of Foo take the argument by const-reference.

like image 42
Kerrek SB Avatar answered Sep 24 '22 21:09

Kerrek SB