C++関数の使用と呼び出し
4614 ワード
概要
本文は主に関数の定義と呼び出し方法を紹介し,関数の一致と実参加形参は紹介内ではない.
1つの関数には、関数名、パラメータ、戻り値の3つの基本要素が必要です.しかし、関数名がない特殊な関数があり、匿名関数と呼ばれています.
関数ベース
関数を呼び出すには、定義または宣言後にする必要があります.そうしないと、「未定義」エラーが表示されます.
同様に,この関数の存在を先に宣言し,後で実現することもできる.
関数ポインタ
定義#テイギ#
ポインタは変数を指すだけでなく、関数を指すこともできます.他のポインタと同様に、関数ポインタは特定のタイプを指します.関数のタイプは、関数名に関係なく、その戻りタイプとパラメータタイプによって決まります.
上記で定義した
宣言を観察すると、
よびだし
関数ポインタを持つと、通常の関数のように呼び出すことができます.
では、関数ポインタを普通のポインタのように、パラメータを通じて別の関数に渡すことができますか?もちろんいいです.
関数オブジェクト
定義#テイギ#
C++11の後、STLには
ポインタ
バイアス関数
さっき使った
関数オブジェクトを渡す
同様に、関数オブジェクトもパラメータとして使用できます.元の
改造後,関数ポインタと同様の効果を達成した.
高次関数
私たちは関数を伝達することができて、それでは私たちももっと高いレベルの関数を実現することができて、例えばHaskellの中の
注意:
Lambda関数
Lambda関数(または匿名関数)は4つの書き方を提供している[2].いくつかの簡略化された計算では、
上では
lambdaと関数オブジェクトがあれば、いつものように外部定義で一度だけ使用した関数を定義する必要はありません.読み取り可能な上で、lambdaと http://en.cppreference.com/w/cpp/utility/functional ↩ http://en.cppreference.com/w/cpp/language/lambda ↩
本文は主に関数の定義と呼び出し方法を紹介し,関数の一致と実参加形参は紹介内ではない.
1つの関数には、関数名、パラメータ、戻り値の3つの基本要素が必要です.しかし、関数名がない特殊な関数があり、匿名関数と呼ばれています.
関数ベース
関数を呼び出すには、定義または宣言後にする必要があります.そうしないと、「未定義」エラーが表示されます.
auto add(const int x, const int y) -> int {
return x + y;
}
int main(int, char **) {
add(1, 2);
return 0;
}
同様に,この関数の存在を先に宣言し,後で実現することもできる.
auto add(const int x, const int y) -> int;
int main(int, char **) {
add(1, 2);
return 0;
}
auto add(const int x, const int y) -> int {
return x + y;
}
関数ポインタ
定義#テイギ#
ポインタは変数を指すだけでなく、関数を指すこともできます.他のポインタと同様に、関数ポインタは特定のタイプを指します.関数のタイプは、関数名に関係なく、その戻りタイプとパラメータタイプによって決まります.
上記で定義した
add
関数を例にとると、add
を指すポインタを宣言するには、関数名をポインタで置き換えるだけでよい.int (*f) (const int x, const y);
f = add;
//
int (*f) (const int x, const y) = add;
宣言を観察すると、
(*f)
は明らかにポインタであり、右側はそのパラメータテーブルであり、関数を指し、左側はその戻りタイプを示している.(*f)
左右の括弧は少なくない.よびだし
関数ポインタを持つと、通常の関数のように呼び出すことができます.
cout << f(1, 2) << endl;
// output: 3
f
はポインタであるため、パラメータリストと戻り値が一致する限り、そのタイプに合致する他の関数を指すこともできます.auto add(const int x, const int y) -> int {
return x + y;
}
int (*f) (const int x, const int y);
f = add;
cout << f(1, 2) << endl;
// output: 3
f = minus;
cout << f(1, 2) << endl;
// output: -1
では、関数ポインタを普通のポインタのように、パラメータを通じて別の関数に渡すことができますか?もちろんいいです.
add
を拡張し、CPSスタイルのadd_cps
を実現することができます.auto add_cps(const int x, const int y, int k (int)) -> int {
auto a = add(x, y);
return k(a);
}
int (*f) (int) = inc;
cout << add_cps(1, 2, f) << endl;
k
は、int (*k) (int)
の書き方と等価な後続計算の関数ポインタである.関数オブジェクト
定義#テイギ#
C++11の後、STLには
ヘッダが設けられ、ここでは多くの関数オブジェクトを処理することができる.std::function
を利用して、関数ポインタと同じ効果を達成することができます.std::function f = add;
cout << f(1, 2) << endl;
ポインタ
f
を関数オブジェクト(funtion objects[1])に変換し、f
のタイプを観察すると、std::function
は関数オブジェクトであることを示し、
のint
は関数の戻り値であり、括弧内は関数のパラメータリストであり、関数ポインタと比較して、それらの表現情報はほとんど変わらない.バイアス関数
さっき使った
inc
関数を覚えていますか?これはadd(1)
のバイアス関数と言えるが,std::bind
を用いてadd
関数を特例化することができる.std::function inc = std::bind(add, 1, std::placeholders::_1);
cout << inc(1) << endl;
// output: 2
std::placeholders::_1
はプレースホルダであり、最初のパラメータがこの位置に埋め込まれることを示し、同様に_2
および他のプレースホルダもある.関数オブジェクトを渡す
同様に、関数オブジェクトもパラメータとして使用できます.元の
add_cps
パラメータリストの関数ポインタを関数オブジェクトに変更します.auto add_cps(const int x, const int y, std::function k) -> int {
auto a = add(x, y);
return k(a);
}
cout << add_cps(1, 2, inc) << endl;
// output: 4
改造後,関数ポインタと同様の効果を達成した.
高次関数
私たちは関数を伝達することができて、それでは私たちももっと高いレベルの関数を実現することができて、例えばHaskellの中の
map
、filter
などです.auto map(std::function f, const vector &in) -> vector {
vector v;
for (const auto &i : in) {
v.push_back(f(i));
}
return v;
}
auto filter(std::function f, const vector &in) -> vector {
vector v;
for (const auto &i : in) {
if (f(i)) {
v.push_back(i);
}
}
return v;
}
注意:
map
はC++でデータ構造を表し、ここではデモのみを行う.Lambda関数
Lambda関数(または匿名関数)は4つの書き方を提供している[2].いくつかの簡略化された計算では、
add
やinc
などの具名関数を再定義する以外に、ある場所で一時的に新しい関数を使用することもでき、このときlambdaに渡すことができます.上では
map
関数を実現し、各数に(+ 1)
を受け入れたいと考えています.map
は関数を受け入れています.ここではlambdaを一時的に使用することができます.std::vector v{1, 2, 3};
map([](auto i) { return i + 1; }, v);
// 2 3 4
[](auto i) { return i + 1; }
はlambda関数であり、匿名関数をstd::function
に割り当てて、関数オブジェクトに再変更することもできます.std::function inc = [](auto i) {
return i + 1;
};
showVec(map(inc, v));
lambdaと関数オブジェクトがあれば、いつものように外部定義で一度だけ使用した関数を定義する必要はありません.読み取り可能な上で、lambdaと
function
を組み合わせると直感的になるかもしれないと思います.