4

缩小范围:我目前正在使用Boost.Unordered。我看到两种可能的解决方案:

  1. 定义我自己的平等谓词和散列函数,并利用模板(也许is_pointer)来区分指针和实例;

  2. 简单地boost::hash通过提供hash_value(Type* const& x)散列来扩展;并将==运算符重载添加为带有参数的自由函数,(Type* const& x, Type* const& y)以进行相等性检查。

我不确定这两种变化是否真的可行,因为我没有测试它们。我想知道你处理这个问题。欢迎实施:)

编辑1: 这个呢?

template<class T>
struct Equals: std::binary_function<T, T, bool> {
    bool operator()(T const& left, T const& right) const {
        return left == right;
    }
};

template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
    bool operator()(T* const& left, T* const& right) const {
        return *left == *right;
    }
};

编辑2:

我刚刚定义:

friend std::size_t hash_value(Base const& base) {
    boost::hash<std::string> hash;

    return hash(base.string_);
}

friend std::size_t hash_value(Base* const& base) {
    return hash_value(*base);
}

进而:

Derived d1("x");
Derived d2("x");

unordered_set<Base*> set;

set.insert(&d1);

assert(set.find(&d2) == end());

调试器说friend std::size_t hash_value(Base* const& base)永远不会调用(GCC 4.7)。这是为什么?

编辑 3: 我发现template <class T> std::size_t hash_value(T* const& v)boost/functional/hash.hpp第 215 行(Boost 1.49)是 Boost 对指针的专门化,它只是掩盖了您在EDIT 2hash_value中的自定义实现,例如我的。因此,这里似乎唯一的方法是创建一个自定义 Hash Functor。

4

2 回答 2

5

对于散列函数,您可以选择专门化boost::hash(或std::hash在较新的标准中)或定义新的仿函数类。这些替代方案同样有效。

对于相等运算符,您需要定义一个新的仿函数,因为您不能在指针上重新定义相等运算符。它是一个内置运算符(在函数术语中定义为bool operator==( T const *x, T const *y ))并且不能被替换。

这两者都可以通过operator()在非模板类中使用模板来通用定义。

struct indirect_equal {
    template< typename X, typename Y >
    bool operator() ( X const &lhs, Y const &rhs )
        { return * lhs == * rhs; }
};

对哈希器遵循类似的模式。

于 2012-04-08T13:15:30.133 回答
1

考虑到原始帖子中的所有编辑,我想提供满足我需求的完整解决方案:

1.平等:

template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
    bool operator()(T const& left, T const& right) const {
        ::std::equal_to<T> equal;

        return equal(left, right);
    }
};

template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
    bool operator()(T* const & left, T* const & right) const {
        Equal<T> equal;

        return equal(*left, *right);
    }
};

2. 散列:

template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
    ::std::size_t operator()(T const & value) const {
        ::boost::hash<T> hash;

        return hash(value);
    }
};

template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
    ::std::size_t operator()(T* const & value) const {
        Hash<T> hash;

        return hash(*value);
    }
};

所以现在我可以继续使用 Boost hash_value,并且它不会被 Boost 的默认实现屏蔽为指针类型(参见EDIT 3)。

3. 示例:

在我的应用程序中,我有一个薄包装器unordered_set,现在看起来像这样:

template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:

// code omitted...

    bool contains(const T& element) const {
        return s_.find(element) != end();
    }

    bool insert(const T& element) {
        return s_.insert(element).second;
    }

// code omitted...

private:
    ::boost::unordered::unordered_set<T, H, E> s_;
};

所以如果我们有一些基类:

class Base {
public:
    Base(const ::std::string& string) {
        if (string.empty())
            throw ::std::invalid_argument("String is empty.");

        string_ = string;
    }

    virtual ~Base() {
    }

    friend bool operator==(const Base& right, const Base& left) {
        return typeid(right) == typeid(left) && right.string_ == left.string_;
    }

    friend bool operator!=(const Base& right, const Base& left) {
        return !(right == left);
    }

    friend ::std::size_t hash_value(Base const& base) {
        ::boost::hash<std::string> hash;

        return hash(base.string_);
    }

    friend ::std::size_t hash_value(Base* const& base) {
        return hash_value(*base);
    }

private:
    ::std::string string_;
};

还有一些派生类:

class Derived: public Base {
public:
    Derived(const ::std::string& string) :
            Base(string) {
    }

    virtual ~Derived() {
    }
};

然后我们甚至可以使用多态性(顺便说一句,这是我的主要意图):

Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");

Set<Base*> set;

set.insert(&d1);

assert(set.contains(&d2));

希望这可以帮助。欢迎任何建议。

于 2012-04-08T18:21:09.720 回答