呼び出し可能オブジェクト
6624 ワード
A successful book is not made of what is in it, but what is left out of it.
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ ㅤㅤㅤ— Mark Twain
1.一般的な関数標準C関数 クラスメンバー関数
説明すると、クラス静的関数
一般的な関数,クラスのメンバー関数,クラスの静的手法については,読者がよく知っていると信じているが,
上記の使い方はあまり使われていませんが、
2.関数ポインタ
関数ポインタ(function pointer)関数アドレスを格納する変数で、この変数で関数を呼び出すことができます.
3.擬似関数
実際には、
また、ジェネレータ
動作原理は非常に簡単で、一元シミュレーション関数
名前の通り、このシミュレーション関数は伝達された値に対して立方演算を行い、この述語 一元シミュレーション関数の一般的な用途は、述語(predict)として使用される.すなわち、パラメータが1つしかなく、
使用例を挙げる
上記の例では、二元模倣関数
4. lambda例 を見てください
私たちは上で実現したシミュレーション関数構文
説明 をキャプチャするためのキャプチャリスト
[]任意の変数を取り込む[&]外部作用ドメイン内のすべての変数を取り込み、参照として匿名関数体において[=]を用いて外部作用ドメイン内のすべての変数を取り込み、匿名関数体において[x,&y]xを用いる値で取り込み、yを参照で取り込む[&,x]xを値で取り込むコピーする.その他の変数は参照によって取り込む[=,&y]yは参照によって取り込む.他の変数は、現在のクラスのthisポインタを値で取得します.すでに使用されている場合は、&または=デフォルトでこのオプションを追加します. 匿名関数にパラメータがない場合は、(param list)部分を省略できます. C++14以降は省略可能 5.std::functionパッケージ関数オブジェクト作用 関数ポインタ(一般関数、クラスメンバー関数、クラス静的メンバー関数を含む)、シミュレーション関数、例 フォーマットの定義:
6. End
勉強を続ける...
ㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ ㅤㅤㅤ— Mark Twain
C++ 2.0
に触れてからもうしばらく経ちましたが、C++
で関数と考えられているもの、あるいは関数に似ているものを簡単にまとめてみましょう.標準的なCとC++関数から関数オブジェクトとlambda式までゆっくり話します.1.一般的な関数
C++
には関数を定義する方法がたくさんありますが、以下に例を挙げて説明します.よく知られている概念がいくつかあります.bool greater(int arg1, int arg2) { return arg1 > arg2; }
struct number {
bool greater(int arg1, int arg2) { return arg1 > arg2; }
};
説明すると、
C++
の中で私は一般的にstruct
を使ってクラスを定義するだけで、伝統的なclass
を使うのではなく、後の私のすべての文字はこのようにして、これは純粋に個人のプログラミングスタイルで、読者は自分の習慣を維持して、いつものように堅持すればいいです.struct number {
static bool greater(int arg1, int arg2) { return arg1 > arg2; }
};
一般的な関数,クラスのメンバー関数,クラスの静的手法については,読者がよく知っていると信じているが,
C++ 2.0
の新しい関数定義を紹介する.C++ 2.0
の新しい関数c++11
は、関数の最後に関数の戻りタイプを説明する新しい関数の書き方を提供し、関数の最初にauto
キーワードを使用します.この使用法は主に関数テンプレートの作成に使用されます.// C++ 11
auto greater(int arg1, int arg2) -> bool { /* */
return arg1 > arg2;
}
上記の使い方はあまり使われていませんが、
c++14
以降は戻り値のタイプを完全に無視することができますが、コンパイラがreturn
文に基づいて自動的に推定します.ここでは関連内容が多く、詳細には展開されません.簡単に2つの例を挙げます.// C++ 14
int value = 3;
auto answer() { return value ; } /* int */
const auto& answer() { return value ; } /* const int& */
// decltype
decltype(auto) answer() { return value ; }
2.関数ポインタ
関数ポインタ(function pointer)関数アドレスを格納する変数で、この変数で関数を呼び出すことができます.
c++11
の前に、一般にtypedef
キーワードを使用して関数ポインタタイプを定義し、c++11
の後に、より表現力のあるusing
を使用して置き換えることができる.bool greater(int arg1, int arg2) { return arg1 > arg2; }
// C++11
typedef bool (*old_cmp)(int, int);
old_cmp cmp = greater;
// C++11
using new_cmp = bool (*)(int, int);
new_cmp cmp = greater;
3.擬似関数
実際には、
C++
において、関数のようなオブジェクトを定義し、使用することができ、それらは擬似関数(Functor)と呼ばれる.本質的には、リロードされた呼び出しオペレータのクラス(call operator)、すなわちoperator()
のクラスを定義し、任意の数と任意のタイプのパラメータを持つことができる.struct functor {
return_type operator()(args...) const { ... }
};
また、
operator()
に含まれる0個、1個または2個のパラメータに従って、このFunctorをそれぞれジェネレータ、1元模倣関数または2元模倣関数と呼び、以下にそれぞれ例を挙げて説明する.struct increase_generator {
int operator()() noexcept { return num++; }
private:
int num = 0;
};
動作原理は非常に簡単で、
increase_generator::operator()
が呼び出されるたびに、メンバー変数num
の値が返され、numの値が1増加します.int main() {
increase_generator num_generator;
for (int i = 0; i < 3; ++i) {
std::cout << num_generator() << std::endl;
}
}
// output: 0 1 2
struct cube {
constexpr int operator()(const int value) const noexcept { return value * value * value; }
};
名前の通り、このシミュレーション関数は伝達された値に対して立方演算を行い、この
operator()
はconstとして宣言され、その行為は数学上の純粋な関数、すなわち副作用がないことに似ている.ここのconstexpr
の役割は、興味のある読者が自分で研究することができます.bool
の値を返すシミュレーション関数である.次のようになります.struct is_even {
constexpr bool operator()(const int value) const noexcept { return (value % 2) == 0; }
};
使用例を挙げる
int main() {
std::vector numbers{1, 2, 3, 4, 5};
numbers.erase(std::remove_if(std::begin(numbers), std::end(numbers), is_even()),
std::end(numbers));
std::copy(std::begin(numbers), std::end(numbers), std::ostream_iterator{std::cout, " "});
return 0;
}
// output: 1 3 5
上記の例では、
Erase-remove
の慣用法を使用し、私たちが定義したis_even
のシミュレーション関数と組み合わせて、vector
の偶数要素の削除を実現しました.struct greater {
bool operator()(const auto& v1, const auto& v2) const noexcept { return v1 > v2; }
};
4. lambda
私たちは上で実現したシミュレーション関数
is_even
を、同様にlambda
で実現し、以下のようにします.auto is_even = [] (auto item) { return (item % 2) == 0; };
is_even(2); // true
lambda
を用いた実装はより短く、表現力もより豊富であることがわかるが、通常、lambda
式の使用は、適用時に実装されるインライン実装、すなわち実装される.注意:上の構文はC++14以上のコンパイラをサポートする必要があります.[capture list] (param list) -> return_type { lambda body;}
説明
[capture list]
外層変数[]任意の変数を取り込む[&]外部作用ドメイン内のすべての変数を取り込み、参照として匿名関数体において[=]を用いて外部作用ドメイン内のすべての変数を取り込み、匿名関数体において[x,&y]xを用いる値で取り込み、yを参照で取り込む[&,x]xを値で取り込むコピーする.その他の変数は参照によって取り込む[=,&y]yは参照によって取り込む.他の変数は、現在のクラスのthisポインタを値で取得します.すでに使用されている場合は、&または=デフォルトでこのオプションを追加します.
(param list)
パラメータリスト-> return_type
戻り値タイプ{ lambda body;}
関数実装std::function
は呼び出し可能オブジェクトパッケージであり、上述したすべての呼び出し可能オブジェクトを収容するクラステンプレートであり、関数、関数オブジェクト、関数ポインタを統一的に処理し、それらの実行を保存および遅延させることができる.lambda
式をタイプ削除します.つまり、これらの呼び出し可能なエンティティをstd::function
タイプに変換できます.std::function
bool greater_global(int arg1, int arg2) { return arg1 > arg2; } //
struct number {
bool greater_member(int arg1, int arg2) { return arg1 > arg2; } //
static bool greater_static(int arg1, int arg2) { return arg1 > arg2; } //
};
//
struct greater_functor {
bool operator()(int arg1, int arg2) const noexcept { return arg1> arg2; }
};
auto greater_lambda = [] (int arg1, int arg2) { return arg1 > arg2; }; // lambda
auto greater_lambda2 = [] (auto arg1, auto arg2) { return arg1 > arg2; }; // lambda
int main() {
std::function test_function;
test_function = greater_global;
number object;
test_function = std::bind(&number::greater_member, &object,
std::placeholders::_1, std::placeholders::_2);
test_function = std::bind(&number::greater_static,
std::placeholders::_1, std::placeholders::_2);
test_function = greater_lambda ;
test_function = greater_lambda2;
test_function = greater_functor();
test_function(3, 2);
}
6. End
勉強を続ける...