C++11 std::set ラムダ比較関数
質問内容
私は
std::set
をカスタム比較関数で作りたいのです。それをクラスとして定義するには
operator()
でクラスとして定義することもできますが、ラムダが使われる場所でラムダを定義できることを楽しみたかったので、ラムダ関数を、クラスとして定義したクラスのコンストラクタの初期化リストで定義することにしました。
std::set
をメンバーとして持つクラスのコンストラクタの初期化リストにラムダ関数を定義することにしました。しかし、ラムダの型がわからない。先に進む前に、例を挙げておきます。
class Foo
{
private:
std::set<int, /*???*/> numbers;
public:
Foo () : numbers ([](int x, int y)
{
return x < y;
})
{
}
};
検索した結果、2つの解決策を見つけました。
std::function
. ただ、セット比較関数の型が
std::function<bool (int, int)>
にして、私がやったように正確にラムダを渡します。2つ目の解決策は、make_set関数を書くことです。
std::make_pair
.
解決方法1:
class Foo
{
private:
std::set<int, std::function<bool (int, int)> numbers;
public:
Foo () : numbers ([](int x, int y)
{
return x < y;
})
{
}
};
解決方法2:
template <class Key, class Compare>
std::set<Key, Compare> make_set (Compare compare)
{
return std::set<Key, Compare> (compare);
}
問題は、1つの解決策を他より好む正当な理由があるかということです。私は標準的な機能(make_setは標準的な関数ではありません)を使用するため、最初のものを好みますが、私は疑問に思っています。
std::function
を使うとコードが遅くなる(可能性がある)のでしょうか? つまり、コンパイラが比較関数をインライン化する可能性が低くなるのか、それともラムダ関数型でなく
std::function
(私は、この場合、ラムダ型であることができないことを知っているが、あなたは知っている、私は一般的に尋ねている) ?
(私はGCCを使っていますが、一般的に人気のあるコンパイラが何をするのか知りたいのです)
要約、私はたくさんの素晴らしい答えを得た後。
速度が重要な場合、最良の解決策は、クラスで
operator()
というファンクタを使うことです。コンパイラが最適化するのが最も簡単で、間接参照も避けられます。
メンテナンスが簡単で、C++11 の機能を使ったより良い汎用的なソリューションのためには
std::function
. これはまだ高速で(ファンクタよりほんの少し遅いですが、無視できる程度かもしれません)、どんな関数でも使うことができます - 。
std::function
ラムダ、呼び出し可能な任意のオブジェクトを使用することができます。
関数ポインタを使用するオプションもありますが、スピードの問題がなければ、私は
std::function
の方が良いと思います(C++11を使用している場合)。
ラムダ関数を別の場所に定義するオプションもありますが、そうすると比較関数がラムダ式であることから何も得るものがありません。
operator()
でクラス化することができ、定義する場所はいずれにせよセット構築にはならないからです。
デリゲーションを使うなど、もっと他のアイデアもあります。すべての解決策についてより徹底した説明が必要な場合は、回答を読んでください :)
どのように解決するのですか?
そうです。
std::function
は、ほぼ不可避なインダイレクトを
set
. コンパイラは理論上、常に
set
's
std::function
は、常に全く同じラムダでそれを呼び出すことを含み、それは難しく、非常に壊れやすいものです。
壊れやすいというのは、コンパイラがその
std::function
へのアクセスが実際にラムダへの呼び出しであることを証明する前に、コンパイラが
std::set
を設定することがないことを証明しなければなりません。
std::function
にはあなたのラムダ以外のものは設定されません。 つまり、ラムダはあなたの
std::set
に到達するすべての可能なルートを追跡し、それらのどれもがそれをしないことを証明しなければならないことを意味します。
これは場合によっては可能かもしれませんが、比較的無害な変更であれば、コンパイラが何とか証明できたとしても、それを破る可能性があります。
一方、ステートレスなファンクタである
operator()
を持つファンクタは挙動を証明するのが簡単で、それを含む最適化は日常茶飯事です。
そうですね、実際には
std::function
の方が遅いかもしれません。 その一方で
std::function
ソリューションの方が
make_set
よりも保守しやすく、プログラマの時間をプログラムのパフォーマンスと交換することは非常に価値があることです。
make_set
には、そのような
set
への呼び出しから型を推測しなければならない、という重大な欠点があります。
make_set
. 多くの場合
set
は永続的な状態を保存するものであり、スタック上で作成した後にスコープから外れるようなものではありません。
静的またはグローバルなステートレス・ラムダを作成した場合
auto MyComp = [](A const&, A const&)->bool { ... }
を使用することができます。
std::set<A, decltype(MyComp)>
の構文で
set
のインスタンスは、持続可能でありながら、コンパイラが最適化しやすいものです。
decltype(MyComp)
のインスタンスはすべてステートレスなファンクタであるため)、インラインで最適化することが容易です。 このことを指摘したのは、あなたが
set
の中に
struct
. (あるいはコンパイラは
struct Foo {
auto mySet = make_set<int>([](int l, int r){ return l<r; });
};
というのは意外でしたね(笑)
最後に、もしあなたがパフォーマンスについて心配しているのなら、次のことを考慮してください。
std::unordered_set
の方がはるかに高速であり (その代償として、内容を順番に反復することができず、 良いハッシュを書いたり探したりしなければなりません)、 ソートされた
std::vector
は、2 段階の "すべてを挿入" それから "内容を繰り返し照会" がある場合に適しています。 単純に詰め込んで
vector
に詰め、次に
sort
unique
erase
を使用すると、無料の
equal_range
アルゴリズムを使用します。
関連
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] リスト内包とラムダ+フィルタの比較
-
[解決済み] Distinct() with lambda?
-
[解決済み] ラムダ(関数)とは何ですか?
-
[解決済み】C++11のラムダ式って何?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】ラムダ関数はテンプレート化できる?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】浮動小数点例外エラーが発生する: 8
-
[解決済み】「std::operator」で「operator<<」にマッチするものがない。
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み】変数やフィールドがvoid宣言されている