std::set
カスタム比較関数でを作成したい。でクラスとして定義することもできますがoperator()
、ラムダを使用する場所で定義できる機能を楽しみたかったので、をstd::set
メンバーとして持つクラスのコンストラクターの初期化リストでラムダ関数を定義することにしました。しかし、ラムダのタイプを取得できません。先に進む前に、次に例を示します。
class Foo
{
private:
std::set<int, /*???*/> numbers;
public:
Foo () : numbers ([](int x, int y)
{
return x < y;
})
{
}
};
検索したところ、2つの解決策が見つかりました。1つは、を使用したものstd::function
です。setの比較関数型をbestd::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);
}
問題は、一方のソリューションをもう一方のソリューションよりも優先する正当な理由があるかどうかです。私は最初のものを好みます。なぜならそれは標準機能を利用しているからです(make_setは標準関数ではありません)が、私は疑問に思います:使用std::function
するとコードが(潜在的に)遅くなりますか?つまり、コンパイラが比較関数をインライン化する可能性を低くしますか、それともラムダ関数タイプであるのとまったく同じように動作するのに十分スマートである必要がありますstd::function
(この場合、ラムダタイプですが、ご存知のとおり、私は一般的に質問しています)?
(私はGCCを使用していますが、一般的なコンパイラーが一般的に何をするのか知りたいです)
要約、私がたくさんの素晴らしい答えを得た後:
operator()
速度が重要な場合、最善の解決策は、別名ファンクターを備えたクラスを使用することです。コンパイラが最適化して間接を回避するのが最も簡単です。
C ++ 11機能を使用して、メンテナンスを容易にし、より優れた汎用ソリューションを実現するには、を使用しますstd::function
。それでも高速で(ファンクターよりも少し遅いですが、無視できるかもしれません)、任意の関数std::function
(ラムダ、呼び出し可能オブジェクト)を使用できます。
関数ポインタを使用するオプションもありますが、速度の問題がない場合は、より良いと思いますstd::function
(C ++ 11を使用する場合)。
ラムダ関数を別の場所で定義するオプションがありますが、比較関数がラムダ式であることからは何も得られません。これは、それをクラスにすることもできoperator()
、定義の場所はとにかくセット構造ではないためです。
委任を使用するなど、さらに多くのアイデアがあります。すべての解決策のより完全な説明が必要な場合は、回答を読んでください:)