unordered_set<Interval>
を作成する次のコードがあります。これは正常にコンパイルされます。
struct Interval {
unsigned int begin;
unsigned int end;
bool updated; //true if concat. initially false
int patternIndex; //pattern index. valid for single pattern
int proteinIndex; //protein index. for retrieving the pattern
};
struct Hash {
size_t operator()(const Interval &interval);
};
size_t Hash::operator()(const Interval &interval){
string temp = to_string(interval.begin) + to_string(interval.end) + to_string(interval.proteinIndex);
return hash<string>()(temp);
}
unordered_set<Interval, string, Hash> test;
ただし、次のコードを使用して挿入しようとすると、コンパイルできません。
for(list<Interval>::iterator i = concat.begin(); i != concat.end(); ++i){
test.insert((*i));
}
さらに、エラーメッセージから問題の原因を特定できません。たとえば、次のようになります。
note: candidate is:
note: size_t Hash::operator()(const Interval&)
note: candidate expects 1 argument, 2 provided
引数を1つだけ指定したと思いました...
挿入コードの問題は何ですか?
新しいインスタンス化コードは次のとおりです:unordered_set<Interval, Hash> test;
ただし、次のようなエラーメッセージは引き続き表示されます。
note: candidate is:
note: size_t Hash::operator()(const Interval&) <near match>
note: no known conversion for implicit ‘this’ parameter from ‘const Hash*’ to ‘Hash*’
最初の問題:
string
を、unordered_set<>
クラステンプレートのインスタンス化の2番目のテンプレート引数として渡します。 2番目の引数は、ハッシュ関数のタイプである必要があります 、およびstd::string
は呼び出し可能なオブジェクトではありません。
おそらく書くつもりです:
unordered_set<Interval, /* string */ Hash> test;
// ^^^^^^^^^^^^
// Why this?
また、(メンバー)変数にはbegin
およびend
以外の名前を使用することをお勧めします。これらはC++標準ライブラリのアルゴリズムの名前です。
2番目の問題:
hasher関数はconst
として修飾する必要があることを覚えておく必要があるため、ファンクターは次のようになります。
struct Hash {
size_t operator() (const Interval &interval) const {
// ^^^^^
// Don't forget this!
string temp = to_string(interval.b) +
to_string(interval.e) +
to_string(interval.proteinIndex);
return (temp.length());
}
};
3番目の問題:
最後に、std::unordered_set
がInterval
タイプのオブジェクトを処理できるようにするには、ハッシュ関数と一致する等価演算子を定義する必要があります。デフォルトでは、std::unordered_set
クラステンプレートの3番目のパラメーターとして型引数を指定しない場合、operator ==
が使用されます。
現在、クラスInterval
にoperator ==
のオーバーロードがないため、オーバーロードを提供する必要があります。例えば:
inline bool operator == (Interval const& lhs, Interval const& rhs)
{
return (lhs.b == rhs.b) &&
(lhs.e == rhs.e) &&
(lhs.proteinIndex == rhs.proteinIndex);
}
結論:
上記のすべての変更後、この ライブ例 でコードがコンパイルされるのを確認できます。
Andy Prowlは完全に 問題を修正 とコードで考えています。ただし、次のメンバー関数をInterval
に追加すると、2つの間隔が同じになる理由が記述されます。
std::string getID() const { return std::to_string(b) + " " + std::to_string(e) + " " + std::to_string(proteinIndex); }
Andy Prowlの提案にも従い、メンバーの名前をbegin
からb
に、end
をe
に変更したことに注意してください。次に、ハッシュ関数と比較関数を ラムダ式 を使用して簡単に定義できます。その結果、unordered_set
次のように:
auto hash = [](const Interval& i){ return std::hash<std::string>()(i.getID()); };
auto equal = [](const Interval& i1, const Interval& i2){ return i1.getID() == i2.getID(); };
std::unordered_set<Interval, decltype(hash), decltype(equal)> test(8, hash, equal);
最後に、読みやすさの理由から、for
ループを範囲ベースのfor
ループに変換しました。
std::list<Interval> concat {{1, 2, false, 3, 4}, {2, 3, false, 4, 5}, {1, 2, true, 7, 4}};
for (auto const &i : concat)
test.insert(i);
for (auto const &i : test)
std::cout << i.b << ", " << i.e << ", " << i.updated << std::endl;
出力(各Interval
の最初の3つのメンバーを出力しました):
2、3、0
1、2、0
ご覧のとおり、印刷される間隔は2つだけです。 3番目({1, 2, true, 7, 4}
)はconcat
に挿入されませんでした。そのb
、e
、およびproteinIndex
は最初の間隔({1, 2, false, 3, 4}
)。