符合C ++ 11标准的自定义键设置(key_type不是value_type,而是functor获取值的键)

时间:2014-08-03 14:06:55

标签: c++ c++11 stl set

我正在搜索具有类似集合容器的模板库,允许使用不同的密钥进行搜索。我不想要地图(密钥复制)并且想要符合C ++ 11的代码(C ++ 14添加template<class K> iterator std::set::find(const K& x)可以在std::set<T*,my_transparent_deref_less<T*> >中使用自定义比较函数。)

你知道吗? 会加强添加吗?或者它已经存在?

签名应如下所示:the_set<T, GetKey, Compare> 我希望针对大小/内存使用(因此flat_set / btree_set)和搜索速度进行优化的结构(插入/删除速度不是那很关键)。 示例:

class User {
public:
    User(const char *name);
    const char *name();
... };
the_set<User*,const char*> USERS([](User* u) { u->name(); },
  [](const char* lhs, const char* rhs) { strcmp(lhs, rhs) < 0; });

我发现red-black-tree in boost::detail看起来像我想要的那样 - 签名是template <class Key, class Value, class KeyOfValue, class KeyCompare, class A> class rbtree。我可以使用flat_setbtree_set这样的东西吗(不用担心使用不公开使用但有目的隐藏为细节的东西)?

原因:我计划将这些设置用于许多对象和许多键(可能是同一对象的不同键/组)。
USERS,UNITS,... - 全局使用btree_set,可能类似于boost::multi_index
User :: units,... - 使用flat_set

设置对象

到目前为止我的代码:(问题是我现在必须使用StringWrapper

#include <set>
#include <iostream>
#include <type_traits>
#include "btree_set.h"
#include "boost/container/flat_set.hpp"

// dereferencing comparator
template <class T>
  class less: public std::less<T> {
public:
    typename std::enable_if<std::is_pointer<T>::value,
      bool>::type operator() (T lhs, T rhs) const {
        return *lhs < *rhs; }};

// here I can change underlying structure to btree_set or std::set
template <class T,
  class C = less<T>,
  class A = std::allocator<T> >
  using default_set = boost::container::flat_set<T, C, A>;

// this works fine for classes derived from their primary key
template <class T, class K = T,
  class B = default_set<K*> >
  class object_set {
private:
    typename std::enable_if<std::is_base_of<K, T>::value,
      B>::type impl;
public:
    template<class... Args>
      T* add(K* key, Args&& ...args) {
        auto it = impl.insert(key);
        if (!it.second) return nullptr;
        T* value = new T(*key, std::forward<Args>(args)...);
        *it.first = value;
        return value; }
    T* operator[](K* key) {
        auto it = impl.find(key);
        if (it == impl.end()) return nullptr;
        return (T*)*it; }
    T* remove(K* key) {
        auto it = impl.find(key);
        if (it == impl.end()) return nullptr;
        T* value = (T*)*it;
        impl.erase(it);
        return value; }
public:
    template<class... Args>
      T* add(K key, Args&& ...args) {
        return add(&key, std::forward<Args>(args)...); }
    T* operator[](K key) {
        return (*this)[&key]; }
    T* remove(K key) {
        return remove(&key); }};

// workaround for above std::is_base_of constraint
class StringWrapper {
    const char *data;
public:
    StringWrapper(const char *data) {
        this->data = data; }
    operator const char *() const {
        return data; }};

// example of class I want to use the container on
class User: public StringWrapper {
public:
    User(const char *name): StringWrapper(name) {}};

// testing
object_set<User,StringWrapper> USERS;
int main() {
    USERS.add("firda"); USERS.add("firda2");
    User* firda = USERS["firda"];
    delete USERS.remove(firda);
    delete USERS.remove("firda2"); }

4 个答案:

答案 0 :(得分:0)

听起来像是boost::multi_index

的工作

http://www.boost.org/doc/libs/1_55_0/libs/multi_index/doc/index.html

答案 1 :(得分:0)

这就是我的意思:

#include "boost/container/flat_set.hpp"

template<class T, class K, class GetKey, class CmpKey>
  class fset {
private:
    boost::container::container_detail::flat_tree<
      K, T*, GetKey, CmpKey, std::allocator<T*> >
      impl;
public:
    template<class... Args>
      T* add(K key, Args&& ...args) {
        auto it = impl.lower_bound(key);
        if (it != impl.end() && impl.key_comp()(key, GetKey()(*it))) {
            return nullptr; }
        T* value = new T(key, std::forward<Args>(args)...);
        impl.insert_unique(it, value);
        return value; }
    T* operator[](K key) {
        auto it = impl.find(key);
        if (it == impl.end()) return nullptr;
        return *it; }
    T* remove(K key) {
        auto it = impl.find(key);
        if (it == impl.end()) return nullptr;
        T* value = *it;
        impl.erase(it);
        return value; }};

class User {
private:
    const char *name_;
public:
    User(const char *name) {
        std::size_t size = std::strlen(name) + 1;
        char *buf = new char[size];
        std::memcpy(buf, name, size);
        name_ = buf; }
    ~User() {
        delete[] name_; }
    const char *name() const {
        return name_; }
public:
    struct get_name {
        const char *operator()(User* u) const {
            return u->name(); }};
    struct cmp_name {
        bool operator()(const char* lhs, const char* rhs) const {
            return std::strcmp(lhs, rhs) < 0; }};};

fset<User,const char*,User::get_name,User::cmp_name>
  USERS;

int main() {
    USERS.add("firda");
    User* firda = USERS["firda"];
    delete USERS.remove("firda"); }

我现在应该关闭或删除此问题吗?

答案 2 :(得分:0)

这就是我现在使用的(查看struct vset_adaptor

#ifndef HEADER___VECTSET___BE8EB41D7B3971E1
#define HEADER___VECTSET___BE8EB41D7B3971E1
#include <vector>
//############################################################### ptrvect
template <class T, class base = std::vector<T*> >
  class ptrvect: public base {
public:
    class iterator: public base::iterator {
        friend class ptrvect;
    private:
        iterator(const typename base::const_iterator& it):
          base::iterator(const_cast<T**>(&*it)) {
            return; }
    public:
        iterator(const typename base::iterator& it):
          base::iterator(it) {
            return; }
        T* operator->() const {
            return **this; }};
    class const_iterator: public base::const_iterator {
    public:
        const_iterator(const typename base::const_iterator& it):
          base::const_iterator(it) {
            return; }
        const_iterator(const typename base::iterator& it):
          base::const_iterator(it) {
            return; }
        T* operator->() const {
            return **this; }};
    template <class It = iterator>
      class condpair: public std::pair<It,bool> {
    public:
        condpair(It it, bool second):
          std::pair<It,bool>(it, second) {
            return; }
        T* operator->() const {
            return *std::pair<It,bool>::first; }};
public:
    iterator begin() {
        return iterator(base::begin()); }
    iterator end() {
        return iterator(base::end()); }
    const_iterator begin() const {
        return const_iterator(base::begin()); }
    const_iterator end() const {
        return const_iterator(base::end()); }
public: // workarounds for pre-C++11 / bad C++11 implementation (should allow const_iterator)
    iterator insert(const_iterator pos, T* value) {
        return base::insert(iterator(pos), value); }
    iterator erase(const_iterator pos) {
        return base::erase(iterator(pos)); }
public: // addons
    iterator find (T* key) {
        return std::find(begin(), end(), key); }
    const_iterator find (T* key) const {
        return std::find(begin(), end(), key); }
    bool contains (T* key) const {
        return find(key) != end(); }
    T* remove(T* key) {
        auto it = find(key);
        if (it == end()) return null;
        T* val = *it;
        base::erase(it);
        return val; }
    T* add(T* val) {
        base::push_back(val);
        return val; }
    void release() {
        for (T* it : *this) delete it;
        base::clear(); }};
//########################################################## vset adaptor
template <class T, class K>
  struct vset_adaptor {
    K operator()(T* it) const {
        return (K)(*it); }
    bool operator()(K lhs, K rhs) const {
        return lhs < rhs; }};
template <class T>
  struct vset_adaptor<T,T*> {
    T* operator()(T* it) const {
        return it; }
    bool operator()(T* lhs, T* rhs) const {
        return lhs < rhs; }};
//================================================================== vset
template <class T, class K=T*, class F = vset_adaptor<T,K> >
  class vset {
private:
    ptrvect<T> impl;
    struct Comp {
        F f;
        K operator()(T* it) const {
            return f(it); }
        bool operator()(K lhs, K rhs) const {
            return f(lhs, rhs); }
        bool operator()(T* lhs, K rhs) const {
            return f(f(lhs), rhs); }
        bool operator()(K lhs, T* rhs) const {
            return f(lhs, f(rhs)); }
        bool operator()(T* lhs, T* rhs) const {
            return f(f(lhs), f(rhs)); }};
    Comp comp;
public:
    typedef typename ptrvect<T>::const_iterator iterator, const_iterator;
    typedef unsigned size_type;
    typedef T *value_type;
    typedef K key_type;
    typedef typename ptrvect<T>::template condpair<iterator> condpair;
public:
    iterator begin() const {
        return iterator(impl.begin()); }
    iterator end() const {
        return iterator(impl.end()); }
    size_type size() const {
        return impl.size(); }
    bool empty() const {
        return impl.empty(); }
public:
    iterator lower_bound(K key) const {
        return std::lower_bound(impl.begin(), impl.end(), key, comp); }
    iterator upper_bound(K key) const {
        return std::upper_bound(impl.begin(), impl.end(), key, comp); }
    std::pair<iterator, iterator> equal_range(K key) const {
        return std::equal_range(impl.begin(), impl.end(), key, comp); }
    iterator find(K key) const {
        iterator it = lower_bound(key);
        return it == end() || comp(key, *it) ? end() : it; }
    bool contains(K key) const {
        iterator it = lower_bound(key);
        return it != end() && !comp(key, *it); }
public:
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type lower_bound(T* key) const {
        return std::lower_bound(impl.begin(), impl.end(), comp(key), comp); }
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type upper_bound(T* key) const {
        return std::upper_bound(impl.begin(), impl.end(), comp(key), comp); }
    typename std::enable_if<!std::is_same<T*,K>::value,
      std::pair<iterator, iterator> >::type equal_range(T* key) const {
        return std::equal_range(impl.begin(), impl.end(), comp(key), comp); }
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type find(T* key) const {
        iterator it = lower_bound(comp(key));
        return it == end() || comp(key, *it) ? end() : it; }
public:
    template<class... Args>
      condpair emplace(K key, Args&& ...args) {
        iterator it = lower_bound(key);
        if (it == end() || comp(key, *it)) {
            return condpair(impl.insert(it,
              new T(key, std::forward<Args>(args)...)), true); }
        return condpair(it, false); }
    iterator erase(iterator at) {
        return impl.erase(at); }
public:
    T* add(T* value) {
        iterator it = lower_bound(value);
        if (it == end() || comp(comp(value), *it)) {
            impl.insert(it, value);
            return value; }
        return nullptr; }
    template<class... Args>
      T* add(K key, Args&& ...args) {
        iterator it = lower_bound(key);
        if (it == end() || comp(key, *it)) {
            T* value = new T(key, std::forward<Args>(args)...);
            impl.insert(it, value);
            return value; }
        return nullptr; }
    T* get(K key) const {
        iterator it = find(key);
        return it == impl.end() ? nullptr : *it; }
    T* operator[](K key) const {
        return *emplace(key).first; }
    T* remove(K key) {
        iterator it = find(key);
        if (it == impl.end()) return nullptr;
        T* value = *it;
        impl.erase(it);
        return value; }
    typename std::enable_if<!std::is_same<T*,K>::value,
      T*>::type remove(T* key) {
        return remove(comp(key)); }
    void release() {
        for (T* it : *this) {
            delete it; }
        impl.clear(); }
    void clear() {
        impl.clear(); }};
#endif

....如果你想知道代码拼写,它是我自己的预处理器的输出。这是真正的代码:

#include <vector>
//############################################################### ptrvect
template <class T, class base = std::vector<T*> >
  class ptrvect: public base
public:
    class iterator: public base::iterator
        friend class ptrvect
    private:
        iterator(const typename base::const_iterator& it):
          base::iterator(const_cast<T**>(&*it))
            return
    public:
        iterator(const typename base::iterator& it):
          base::iterator(it)
            return
        T* operator->() const
            return **this
    class const_iterator: public base::const_iterator
    public:
        const_iterator(const typename base::const_iterator& it):
          base::const_iterator(it)
            return
        const_iterator(const typename base::iterator& it):
          base::const_iterator(it)
            return
        T* operator->() const
            return **this
    template <class It = iterator>
      class condpair: public std::pair<It,bool>
    public:
        condpair(It it, bool second):
          std::pair<It,bool>(it, second)
            return
        T* operator->() const
            return *std::pair<It,bool>::first
public:
    iterator begin()
        return iterator(base::begin())
    iterator end()
        return iterator(base::end())
    const_iterator begin() const
        return const_iterator(base::begin())
    const_iterator end() const
        return const_iterator(base::end())
public: // workarounds for pre-C++11 / bad C++11 implementation (should allow const_iterator)
    iterator insert(const_iterator pos, T* value)
        return base::insert(iterator(pos), value)
    iterator erase(const_iterator pos)
        return base::erase(iterator(pos))
public: // addons
    iterator find (T* key)
        return std::find(begin(), end(), key)
    const_iterator find (T* key) const
        return std::find(begin(), end(), key)
    bool contains (T* key) const
        return find(key) != end()
    T* remove(T* key)
        auto it = find(key)
        if it == end(); return null
        T* val = *it
        base::erase(it)
        return val
    T* add(T* val)
        base::push_back(val)
        return val
    void release()
        for T* it : *this; delete it
        base::clear()
//########################################################## vset adaptor
template <class T, class K>
  struct vset_adaptor
    K operator()(T* it) const
        return (K)(*it)
    bool operator()(K lhs, K rhs) const
        return lhs < rhs
template <class T>
  struct vset_adaptor<T,T*>
    T* operator()(T* it) const
        return it
    bool operator()(T* lhs, T* rhs) const
        return lhs < rhs
//================================================================== vset
template <class T, class K=T*, class F = vset_adaptor<T,K> >
  class vset
private:
    ptrvect<T> impl
    struct Comp
        F f
        K operator()(T* it) const
            return f(it)
        bool operator()(K lhs, K rhs) const
            return f(lhs, rhs)
        bool operator()(T* lhs, K rhs) const
            return f(f(lhs), rhs)
        bool operator()(K lhs, T* rhs) const
            return f(lhs, f(rhs))
        bool operator()(T* lhs, T* rhs) const
            return f(f(lhs), f(rhs))
    Comp comp
public:
    typedef typename ptrvect<T>::const_iterator iterator, const_iterator
    typedef unsigned size_type
    typedef T *value_type
    typedef K key_type
    typedef typename ptrvect<T>::template condpair<iterator> condpair
public:
    iterator begin() const
        return iterator(impl.begin())
    iterator end() const
        return iterator(impl.end())
    size_type size() const
        return impl.size()
    bool empty() const
        return impl.empty()
public:
    iterator lower_bound(K key) const
        return std::lower_bound(impl.begin(), impl.end(), key, comp)
    iterator upper_bound(K key) const
        return std::upper_bound(impl.begin(), impl.end(), key, comp)
    std::pair<iterator, iterator> equal_range(K key) const
        return std::equal_range(impl.begin(), impl.end(), key, comp)
    iterator find(K key) const
        iterator it = lower_bound(key)
        return it == end() || comp(key, *it) ? end() : it
    bool contains(K key) const
        iterator it = lower_bound(key)
        return it != end() && !comp(key, *it)
public:
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type lower_bound(T* key) const
        return std::lower_bound(impl.begin(), impl.end(), comp(key), comp)
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type upper_bound(T* key) const
        return std::upper_bound(impl.begin(), impl.end(), comp(key), comp)
    typename std::enable_if<!std::is_same<T*,K>::value,
      std::pair<iterator, iterator> >::type equal_range(T* key) const
        return std::equal_range(impl.begin(), impl.end(), comp(key), comp)
    typename std::enable_if<!std::is_same<T*,K>::value,
      iterator>::type find(T* key) const
        iterator it = lower_bound(comp(key))
        return it == end() || comp(key, *it) ? end() : it
public:
    template<class... Args>
      condpair emplace(K key, Args&& ...args)
        iterator it = lower_bound(key)
        if it == end() || comp(key, *it)
            return condpair(impl.insert(it,
              new T(key, std::forward<Args>(args)...)), true)
        return condpair(it, false)
    iterator erase(iterator at)
        return impl.erase(at)
public:
    T* add(T* value)
        iterator it = lower_bound(value)
        if it == end() || comp(comp(value), *it)
            impl.insert(it, value)
            return value
        return nullptr
    template<class... Args>
      T* add(K key, Args&& ...args)
        iterator it = lower_bound(key)
        if it == end() || comp(key, *it)
            T* value = new T(key, std::forward<Args>(args)...)
            impl.insert(it, value)
            return value
        return nullptr
    T* get(K key) const
        iterator it = find(key)
        return it == impl.end() ? nullptr : *it
    T* operator[](K key) const
        return *emplace(key).first
    T* remove(K key)
        iterator it = find(key)
        if it == impl.end(); return nullptr
        T* value = *it
        impl.erase(it)
        return value
    typename std::enable_if<!std::is_same<T*,K>::value,
      T*>::type remove(T* key)
        return remove(comp(key))
    void release()
        for T* it : *this
            delete it
        impl.clear()
    void clear()
        impl.clear()

答案 3 :(得分:0)

您已经提到了c ++ 14和模板查找功能。以下是谁对此感兴趣的一个简单示例:

#include <iostream>
#include <set>
#include <vector>

using namespace std;

class Info
{
    int          num_;
public:
    explicit Info(int n) : num_(n) {}

    bool operator<(const Info &other) const { return num_ < other.num_; }

    friend inline bool operator<(const Info& lhs, const int& rhs);
    friend bool operator<(const int& lhs,  const Info& rhs);
};

inline bool operator<(const Info& lhs, const int& rhs)  { return lhs.num_ < rhs; }
inline bool operator<(const int& lhs,  const Info& rhs) { return lhs < rhs.num_; }


int main()
{
    // less<> is a is_transparent comparer
    set<Info, less<> > s;
    // insert two items
    s.insert(Info(2));
    s.insert(Info(4));
    // search
    for (auto n : {1,2,3,4,5}) {
        cout << "Searching " << n << (s.find(n) == s.end()?" not found":" found") << endl;
    }
    return 0;
}

结果:

Searching 1 not found
Searching 2 found
Searching 3 not found
Searching 4 found
Searching 5 not found