指向成员的指针集

时间:2014-05-15 10:27:05

标签: c++ pointer-to-member

这不起作用:

struct A {
    int x1;
    int x2;
};

int main() {
    int A::*p1 = &A::x1;

    set<int A::*> s;
    s.insert( p1 );  // compile error:  No operator<
    unordered_set<int A::*> us;
    us.insert( p1 ); // compile error:  No hash function 
}

我必须提供比较函数(用于set)或散列函数(用于unordered_set)。到目前为止,我想出的唯一方法是检查成员指针底层的原始字节:

struct XLess {
    bool operator()( int A::* a, int A::*b ){
        return memcmp( &a, &b, sizeof(a) ) < 0;
    }
};

set<int A::*, XLess> s; // now appears to work

这是创建套装的可靠方法吗?它取决于相同的指针由相同的字节表示。有更好的解决方案吗?

3 个答案:

答案 0 :(得分:1)

您可以展开std::lessstd::hash运营商,BTW这是完全允许的。同样受到SO answer的启发,我创建了size_t getIndexOf(int A::* x)进行散列并进行比较,见下文:

#include <set>
#include <unordered_set>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct A {
  int x1;
  int x2;
};

typedef int (A::*x1);
vector<x1> canon;
size_t getIndexOf(int A::* x) {
  auto it = find(canon.begin(), canon.end(), x);
  if (it != canon.end()) return it - canon.begin();
  canon.push_back(x);
  return canon.size() - 1;
}

namespace std {
  template<> struct less<int A::*> {
    bool operator()(int A::* a, int A::*b){ return getIndexOf(a) < getIndexOf(b); }
  };

  template <> struct hash<int A::*>
  {
    size_t operator()(int A::* x) const
    {
      return  getIndexOf(x);
    }
  };
}

int main() {
  int A::*p1 = &A::x1;
  int A::*p2 = &A::x2;
  set<int A::*> s;
  s.insert(p1);
  s.insert(p2);

  for (auto e : s) std::cout << getIndexOf(e) << std::endl;

  unordered_set<int A::*> us;
  us.insert(p1);
  us.insert(p2);

  for (auto e : us) std::cout << getIndexOf(e) << std::endl;

  return 0;
}

答案 1 :(得分:1)

正式来说,它没有得到保证。在实践中,指向成员的指针 数据很可能只是一个简单的整数类型,而你 应该没问题。对于成员函数的指针,打开 另一方面:这些通常或多或少都很复杂 结构,通常包含填充,其内容为 未定义,所以你的技术不会起作用。

我也注意到,在第一个片段中,您已经使用过 std::unordered_set,而不是std::setstd::unordered_set 不使用排序函数,而是使用等价函数 function(和==是为指向成员的指针定义的)和 哈希函数。当然,实现哈希函数了 与实施订购相同的问题。

说完这个:为什么你想要这样一套呢? 成员指针(例如int A::*)只能指向成员 给定类型的(不是给定类型的数组的成员) 类型),你可以编写成千上万的类 成员。最简单的解决方案可能就是使用 std::vector<int A::*>和线性搜索(std::find) 确定会员资格它可能比任何一个都快 std::set,除非你确实有成千上万的成员。

答案 2 :(得分:0)

您的XLess比较器依赖于标准不保证的一个假设:
成员指针的所有位都是重要的,两个具有不同位模式的成员指针指向不同的成员 尽管如此,只要它们没有指向虚函数,它应该可以解决任何平面内存模型的实现:有两种方法可以指向这些:使用vtable,或包含函数地址。 / p>

另外,AFAICT没有更好的方法,因为你需要了解成员指针内部或者实现提供的比较。