[解決済み] C++でcopy_ifなどの「単項述語」を定義するにはどうしたらいいですか?
質問
std::copy_if()を使おうとしているのですが、その構文がどのように動作するかは、以下の記事からなんとなくわかりました。 http://www.cplusplus.com/reference/algorithm/copy_if/ :
auto it = std::copy_if (foo.begin(), foo.end(), bar.begin(), [](int i){return !(i<0);} );
最後の引数は、私が混乱しているものです。括弧は何のためにあるのでしょうか?私がどこかで書いた関数を引数として使うことはできるのでしょうか、そしてそれはどのように機能するのでしょうか?関数に渡す変数を指定すれば、別の引数を渡すことができるのでしょうか?
全体的な質問としては、これらの構文がどこにあるのか、ということですね。この例を使って、いくつかの本当に簡単なことを宣言することができますが、私はそれを使ってより多くのことができるようにしたいと思います。単項述語が何をすべきで何をすべきでないかを説明する場所はいくつか見つけましたが、実際にどのように宣言すればいいのか、それが何を意味するのかについてはわかりません。私はまだc++のアルゴリズムに慣れていないので、より効果的な使い方を学びたいと思っています。
どのように解決するのですか?
関数のように振る舞うものなら何でも、述語として
copy_if
. よく使われるものがいくつかあります。
1) 関数
関数は確かに関数のように振る舞うので、述語として
copy_if
:
bool is_less_than_zero(int i) { return i < 0; }
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b), is_less_than_zero);
// now b will contain the elements {-2, -1}
}
2)オーバーロードされたオブジェクト
operator()
オブジェクトはオーバーロードすることができます
operator()
というように、関数のように動作します。 これらはしばしば関数オブジェクト、またはファンクタと呼ばれます。 これにより、生の関数では実現できない状態を保存することができます。
struct IsLessThan {
IsLessThan(int i) : i_{i} {}
bool operator()(int i) { return i < i_; }
int i_;
};
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b), IsLessThan(0));
// now b will contain the elements {-2, -1}
}
3) ラムダ
ラムダは概念的には無名関数です。 実際には、オブジェクトの構文上の糖分として、オーバーロードされた
operator()
しかし、そのおかげで、少ないコードで簡単な述語を作成するのに便利なツールとなっています。
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
std::copy_if(a.begin(), a.end(), std::back_inserter(b),
[](int i){ return i < 0; });
// now b will contain the elements {-2, -1}
}
ラムダは実際にはオブジェクトで、オーバーロードされた
operator()
また、ラムダのキャプチャーリストで指定された状態を含むことができます。
int main() {
std::vector<int> a = {1, 2, -2, -1};
std::vector<int> b;
int number_to_compare_to = 0;
std::copy_if(a.begin(), a.end(), std::back_inserter(b),
[number_to_compare_to](int i){ return i < number_to_compare_to; });
// now b will contain the elements {-2, -1}
}
標準ライブラリには、状態を含む関数オブジェクトを簡単に作成し、それを使って関数にパラメータの一部を供給する機能があります (すなわち
std::bind
しかし、ほとんどの場合、ラムダを使う方が簡単です。 つまり、次のコードは、どちらも全く同じ動作をする2つのオブジェクトを作成します。
bool first_less_than_second(int i, int j) { return i < j; }
int main() {
auto bind_less_than_zero = std::bind(first_less_than_second, std::placeholders::_1, 0);
auto lambda_less_than_zero = [](int i){ return first_less_than_second(i, 0); };
}
一般的には、ラムダバージョンの方が好ましいのですが、それでも時々
std::bind
(またはc++11以前のブースト対応版である
boost::bind
)が採用されています。
関連
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】エラー:free(): 次のサイズが無効です(fast)。
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み] リファレンスとポインタの使い分け
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】C++の関数から複数の値を返したい
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】オブジェクト引数のない非静的メンバ関数の呼び出し コンパイラーエラー
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み] 数値定数の前にunqualified-idを付けて、数値を定義することを期待する。
-
[解決済み】C++11のラムダ式って何?