Is this valid C++ (considering the latest standard)? I'm getting compilation errors with near-top-of-tree clang/libc++ on Ubuntu 12.04. If it should be valid, I'll mail the clang-dev list with error messages and such.
#include <functional>
#include <unordered_set>
struct X
{
int i;
};
void f ()
{
std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX;
// Do stuff with setOfReferencesToX
}
** As an aside, I'm tired of qualifying that the question/answer is specific to the latest standard. Could the C++ community as a whole, please start qualifying things that are specific to the old standard instead? The newer standard has been out for about a year now.
A reference_wrapper<Ty> is a copy constructible and copy assignable wrapper around a reference to an object or a function of type Ty , and holds a pointer that points to an object of that type. A reference_wrapper can be used to store references in standard containers, and to pass objects by reference to std::bind .
Unordered sets are containers that store unique elements in no particular order, and which allow for fast retrieval of individual elements based on their value. In an unordered_set, the value of an element is at the same time its key, that identifies it uniquely.
Keys are immutable, therefore, the elements in an unordered_set cannot be modified once in the container - However, they can be inserted and removed. Unordered sets do not allow duplicates and are initialized using comma-delimited values enclosed in curly braces.
An unordered_set is implemented using a hash table where keys are hashed into indices of a hash table so that the insertion is always randomized.
The problem is not specific to std::reference_wrapper<T>
, but rather to the type X
itself.
The issue is that std::unordered_set requires that you define hashing and equality functors for std::reference_wrapper<X>
. You can pass the hash functor as second template parameter.
For example, this would work:
#include <functional> // for std::hash<int>
struct HashX {
size_t operator()(const X& x) const {
return std::hash<int>()(x.i);
}
};
and then
std::unordered_set<std::reference_wrapper<X>, HashX> setOfReferencesToX;
Another option is to make a specialization for std::hash<X>
:
namespace std {
template <>
struct hash<X> {
size_t operator()(const X& x) const {
return std::hash<int>()(x.i);
}
};
}
This allows you to avoid explicitly specifying the 2nd template argument:
std::unordered_set<std::reference_wrapper<X>> setOfReferencesToX;
Concerning the equality comparison, you can fix this by providing an equality operator for class X
:
struct X
{
bool operator==(const X& rhs) const { return i == rhs.i; }
int i;
};
Otherwise, you can define your own functor and pass it as third template argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With