ページへ戻る
印刷
技術系備忘録/C++/小技/std.set map系の比較関数の新機能
をテンプレートにして作成 ::
シンクリッジ
xpwiki
:技術系備忘録/C++/小技/std.set map系の比較関数の新機能 をテンプレートにして作成
開始行:
どういうタイトルがよいかすごく悩みましたが諦めて、結局よ...
タイトル無くてもいいかなくらいに思ったのですが、とりあえ...
~
~
C++ には std::map があります。すごく便利です。
がしかし実際の設計で少々悩むケースもあるかなーと思います...
~
~
本。っていう情報があります。
本のタイトルや値段、ISBN(書籍ID的なコード)などなどを持...
#prettify{{
struct CBook
{
std::string title;
unsigned int price;
std::string isbn;
std::string description;
・
・
};
}}
こういうクラスを作ったとします。
で、たくさんある本の中から ISBN で検索する必要がある場合、
#prettify{{
std::map<std::string,CBook> mapIsbnToBook;
}}
こんな感じで、ISBN 文字列をキーにした map を作りたくなる...
~
~
もちろんこれでOKなんですが庶民感情としては、
値(CBook)の中にある isbn と、map のキーは同じものなのに別...
そこで思いつくのは以下みたいなコード
#prettify{{
struct CIsbnLess
{
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
};
std::set<CBook,CIsbnLess> setBooks;
}}
こんな感じにすれば CBook::isbn がキーを兼ねるので、余計な...
がしかし、このやり方だと検索するときが厄介です。
やりたいことは以下のように
#prettify{{
bool exist = setBooks.find("1234567") != setBooks.end();
}}
ISBN 文字列で検索(find)したいのですが、現実には以下のように
#prettify{{
CBook key;
key.isbn = "1234567";
bool exist = setBooks.find(key) != setBooks.end();
}}
find の引数にはキーの型(CBook)で渡さなきゃならず、さすが...
がしかし、文字列での find はどう頑張っても出来ないので途...
~
~
~
そこで少し視点を変えて、std::set ではなく std::vector を...
#prettify{{
struct CIsbnLess
{
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
bool operator()(const std::string &a,const CBook &b)const{
return a < b.isbn;
}
bool operator()(const CBook &a,const std::string &b)const{
return a.isbn < b;
}
};
std::vector<CBook> books;
// ・・・
std::sort(books.begin(), books.end(), CIsbnLess());
// ・・・
bool exist = std::binary_search( books.begin(), books.end...
}}
これはこれでOKな気がします。
が、欲を言い出すと少々不満が出てしまいます。
というのは、この情報を使う側の立場になったときに、
books の std::vector<CBook> っていう型は、std::set と比べ...
・ISBN でソート済のリストであるということが読み取れない。
・ソートキー(ISBN)が重複してないとは読み取れず、重複して...
っていうあたりが主な理由でちょっと合わないかなという感じ...
やっぱり折角の C++ なので型定義で出来るだけ意図を表したい...
~
~
~
しかし!C++ の進化っぷりはスゴイです。実は C++14 で set::...
(最近知りました。猛省。そしてこの記事で一番言いたいとこ...
#prettify{{
struct CIsbnLess
{
typedef void is_transparent; // ←コレが重要
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
bool operator()(const std::string &a,const CBook &b)const{
return a < b.isbn;
}
bool operator()(const CBook &a,const std::string &b)const{
return a.isbn < b;
}
};
std::set<CBook,CIsbnLess> setBooks;
// ・・・
bool exist = setBooks.find("1234567") != setBooks.end(); ...
}}
これはすごく便利です!
裏技っぽい印象を受けてしまいますが C++14 では ''is_transp...
[[こちらのサイト>https://faithandbrave.hateblo.jp/entry/2...
~
というわけでコレで解決です!
今後も使えるシーンではバリバリ使っていこうと思いました。
ありがとうございました!
~
~
~
~
と、したいのですが、以下少々愚痴を・・。
上記コードを使った場合、例えば本の金額を変更したい場合、...
#prettify{{
std::set<CBook,CIsbnLess> setBooks;
// ・・・
auto i = setBooks.find("1234567");
if( i != setBooks.end() ){
i->price = 500; // エラー
}
}}
std::set/map の仕様でキーは const 扱いになります。
set/map のキーは変更されたらイカンので const 扱いにします...
&font(80%){もちろん const_cast しちゃえば変更出来てしまい...
そこで、正攻法な解の一つとしてはポインタにすることだと思...
#prettify{{
using std::shared_ptr;
struct CIsbnLess
{
typedef void is_transparent;
bool operator()(const shared_ptr<CBook> &a,const shared_...
return a->isbn < b->isbn;
}
bool operator()(const std::string &a,const shared_ptr<CB...
return a < b->isbn;
}
bool operator()(const shared_ptr<CBook> &a,const std::st...
return a->isbn < b;
}
};
std::set<shared_ptr<CBook>,CIsbnLess> setBooks;
auto i = setBooks.find("1234567");
if( i != setBooks.end() ){
(*i)->price = 500; // OK
}
}}
これで一応解決できます。
がしかし、ポインタにすると別のとこで困ることが・・・例え...
#prettify{{
// 書店から本一覧を取得
const std::set<std::shared_ptr<CBook>,CIsbnLess> &setBook...
}}
と、こんな風に、書店側からすれば読み取り専用の情報として...
#prettify{{
for( auto &i : setBooks ){
i->price = 0; // OK
}
}}
変更出来てしまいます。アウチ。
&font(80%){もちろん cast して返しちゃうのもアリかと思うん...
~
個人的希望としては std::set/map のキーを 非const にする方...
~
~
というわけで結論。
#prettify{{
std::map<std::string,CBook> mapIsbnToBook;
}}
この例ではコレが無難かもということで結局一番最初に戻りま...
ありがとうございました!
~
~
~
~
とまぁ、そもそもこんな事で悩むこと自体が間違っているのか...
ありがとうございました。
終了行:
どういうタイトルがよいかすごく悩みましたが諦めて、結局よ...
タイトル無くてもいいかなくらいに思ったのですが、とりあえ...
~
~
C++ には std::map があります。すごく便利です。
がしかし実際の設計で少々悩むケースもあるかなーと思います...
~
~
本。っていう情報があります。
本のタイトルや値段、ISBN(書籍ID的なコード)などなどを持...
#prettify{{
struct CBook
{
std::string title;
unsigned int price;
std::string isbn;
std::string description;
・
・
};
}}
こういうクラスを作ったとします。
で、たくさんある本の中から ISBN で検索する必要がある場合、
#prettify{{
std::map<std::string,CBook> mapIsbnToBook;
}}
こんな感じで、ISBN 文字列をキーにした map を作りたくなる...
~
~
もちろんこれでOKなんですが庶民感情としては、
値(CBook)の中にある isbn と、map のキーは同じものなのに別...
そこで思いつくのは以下みたいなコード
#prettify{{
struct CIsbnLess
{
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
};
std::set<CBook,CIsbnLess> setBooks;
}}
こんな感じにすれば CBook::isbn がキーを兼ねるので、余計な...
がしかし、このやり方だと検索するときが厄介です。
やりたいことは以下のように
#prettify{{
bool exist = setBooks.find("1234567") != setBooks.end();
}}
ISBN 文字列で検索(find)したいのですが、現実には以下のように
#prettify{{
CBook key;
key.isbn = "1234567";
bool exist = setBooks.find(key) != setBooks.end();
}}
find の引数にはキーの型(CBook)で渡さなきゃならず、さすが...
がしかし、文字列での find はどう頑張っても出来ないので途...
~
~
~
そこで少し視点を変えて、std::set ではなく std::vector を...
#prettify{{
struct CIsbnLess
{
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
bool operator()(const std::string &a,const CBook &b)const{
return a < b.isbn;
}
bool operator()(const CBook &a,const std::string &b)const{
return a.isbn < b;
}
};
std::vector<CBook> books;
// ・・・
std::sort(books.begin(), books.end(), CIsbnLess());
// ・・・
bool exist = std::binary_search( books.begin(), books.end...
}}
これはこれでOKな気がします。
が、欲を言い出すと少々不満が出てしまいます。
というのは、この情報を使う側の立場になったときに、
books の std::vector<CBook> っていう型は、std::set と比べ...
・ISBN でソート済のリストであるということが読み取れない。
・ソートキー(ISBN)が重複してないとは読み取れず、重複して...
っていうあたりが主な理由でちょっと合わないかなという感じ...
やっぱり折角の C++ なので型定義で出来るだけ意図を表したい...
~
~
~
しかし!C++ の進化っぷりはスゴイです。実は C++14 で set::...
(最近知りました。猛省。そしてこの記事で一番言いたいとこ...
#prettify{{
struct CIsbnLess
{
typedef void is_transparent; // ←コレが重要
bool operator()(const CBook &a,const CBook &b)const{
return a.isbn < b.isbn;
}
bool operator()(const std::string &a,const CBook &b)const{
return a < b.isbn;
}
bool operator()(const CBook &a,const std::string &b)const{
return a.isbn < b;
}
};
std::set<CBook,CIsbnLess> setBooks;
// ・・・
bool exist = setBooks.find("1234567") != setBooks.end(); ...
}}
これはすごく便利です!
裏技っぽい印象を受けてしまいますが C++14 では ''is_transp...
[[こちらのサイト>https://faithandbrave.hateblo.jp/entry/2...
~
というわけでコレで解決です!
今後も使えるシーンではバリバリ使っていこうと思いました。
ありがとうございました!
~
~
~
~
と、したいのですが、以下少々愚痴を・・。
上記コードを使った場合、例えば本の金額を変更したい場合、...
#prettify{{
std::set<CBook,CIsbnLess> setBooks;
// ・・・
auto i = setBooks.find("1234567");
if( i != setBooks.end() ){
i->price = 500; // エラー
}
}}
std::set/map の仕様でキーは const 扱いになります。
set/map のキーは変更されたらイカンので const 扱いにします...
&font(80%){もちろん const_cast しちゃえば変更出来てしまい...
そこで、正攻法な解の一つとしてはポインタにすることだと思...
#prettify{{
using std::shared_ptr;
struct CIsbnLess
{
typedef void is_transparent;
bool operator()(const shared_ptr<CBook> &a,const shared_...
return a->isbn < b->isbn;
}
bool operator()(const std::string &a,const shared_ptr<CB...
return a < b->isbn;
}
bool operator()(const shared_ptr<CBook> &a,const std::st...
return a->isbn < b;
}
};
std::set<shared_ptr<CBook>,CIsbnLess> setBooks;
auto i = setBooks.find("1234567");
if( i != setBooks.end() ){
(*i)->price = 500; // OK
}
}}
これで一応解決できます。
がしかし、ポインタにすると別のとこで困ることが・・・例え...
#prettify{{
// 書店から本一覧を取得
const std::set<std::shared_ptr<CBook>,CIsbnLess> &setBook...
}}
と、こんな風に、書店側からすれば読み取り専用の情報として...
#prettify{{
for( auto &i : setBooks ){
i->price = 0; // OK
}
}}
変更出来てしまいます。アウチ。
&font(80%){もちろん cast して返しちゃうのもアリかと思うん...
~
個人的希望としては std::set/map のキーを 非const にする方...
~
~
というわけで結論。
#prettify{{
std::map<std::string,CBook> mapIsbnToBook;
}}
この例ではコレが無難かもということで結局一番最初に戻りま...
ありがとうございました!
~
~
~
~
とまぁ、そもそもこんな事で悩むこと自体が間違っているのか...
ありがとうございました。
ページ名: