9

c++ メンバー関数へのポインターをハッシュ (std::tr1::hash または boost::hash) するにはどうすればよいですか?

例:

クラス Class のいくつかの異なるメソッドを指すいくつかの bool (Class::*functionPointer)() (静的ではない) があり、それらのポインターからメンバー関数をハッシュする必要があります。

どうやってやるの?

また、これらのメンバー関数ポインターを比較 (std::less) して、std::set に格納できるようにするにはどうすればよいですか?

4

3 に答える 3

14

メンバー関数へのポインターを含むすべての C++ オブジェクトは、メモリ内で char の配列として表されます。だからあなたは試すことができます:

bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));

ptrptrバイトの配列を指しているものとして扱い、(sizeof(bool (Class::*)()))それらのバイトをハッシュまたは比較します。unsigned char必要に応じて代わりに使用できますchar

これにより、誤検知がないことが保証されます。C++03 では、メンバー関数へのポインターは POD です。これは、特に memcpy を使用してコピーできることを意味します。これは、バイト単位の値が同じであれば、同じであることを意味します。

問題は、メンバー関数ポインターのストレージ表現に、値に関与しないビットが含まれる可能性があることです。そのため、同じメンバー関数への異なるポインターに対して必ずしも同じであるとは限りません。または、コンパイラは、何らかのあいまいな理由で、同じクラスの同じ関数を指す複数の方法を持っている可能性があります。これらはバイト単位で等しくありません。いずれにせよ、偽陰性を得ることができます。メンバー関数ポインターが実装で実際にどのように機能するかを調べる必要があります。何らかの方法でメンバー関数ポインターを実装する必要がありoperator==、その方法がわかれば、おそらく順序とハッシュ関数を理解できるでしょう。

これは難しい可能性があります: メンバー関数ポインターは厄介であり、ストレージには、指している関数の種類 (仮想、継承) に応じて、関与しない「スラック スペース」の量が異なる可能性があります。そのため、おそらくコンパイラの実装の詳細とかなり深く対話する必要があります。次の記事が参考になるかもしれません: http://www.codeproject.com/KB/cpp/FastDelegate.aspx

よりクリーンな代替手段は、すべての関数ポインターを「正規化」するために配列を介して線形検索を実行し、配列内のその関数ポインターの「正規」インスタンスの位置に基づいて比較およびハッシュすることです。パフォーマンス要件が何であるかによって異なります。また、要件があるとしても、クラス (およびその派生クラス) には、線形検索にそれほど時間がかかるほど多くの関数がありますか?

typedef bool (Class::*func)();
vector<func> canon;

size_t getIndexOf(func fn_ptr) {
    vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
    if (it != canon.end()) return it - canon.begin();
    canon.push_back(func);
    return canon.size() - 1;
}
于 2009-08-25T14:25:58.090 に答える
1

前の回答で説明したように、(Microsoft コンパイラ 2010 で) ポインターをキャストできませんでしたが、これは私にとってはうまくいきます:

static string fmptostr(int atype::*opt)
  {
      char buf[sizeof(opt)];
      memcpy(&buf,&opt,sizeof(opt));
      return string(buf,sizeof(opt));
  }

ポインターのビット単位の同一性については、ビット単位でよいため、適切なコンパイラ スイッチが使用されているようです。少なくともこれは、#pragma pointers_to_members とスイッチ.../vmg を使用する Microsoft コンパイラに当てはまります。

于 2011-09-08T14:14:28.683 に答える