関数ポインタ
関数を引数として渡します
「関数ポインタ」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
関数ポインタとは
関数ポインタは関数のアドレスを保持するため、関数を間接的に呼び出したり、データのように渡したりできます。
- 型には関数のシグネチャが記述されます。
- 関数に動作をパラメーターとして渡せるようになります。
#include <iostream>
int add(int a, int b) { return a + b; }
int main() {
int (*op)(int, int) = add;
std::cout << op(3, 4) << '\n';
return 0;
}型を宣言する
int (*op)(int, int)という宣言は、opが2つのintを受け取り、intを返す関数へのポインタであることを表します。*opを囲む括弧は必須です。
#include <iostream>
int square(int x) { return x * x; }
int main() {
int (*fn)(int) = square;
std::cout << fn(5) << '\n';
return 0;
}ポインタ経由で呼び出す
関数ポインタは、関数自体と同じように呼び出せます。明示的にデリファレンスすることもできますが、その必要はほとんどありません。
#include <iostream>
void greet() { std::cout << "Hello\n"; }
int main() {
void (*g)() = greet;
g();
(*g)();
return 0;
}関数を引数として渡す
関数は関数ポインタをパラメーターとして受け取れるため、呼び出し側で独自の動作を組み込めます。
#include <iostream>
int apply(int x, int (*fn)(int)) { return fn(x); }
int doubler(int n) { return n * 2; }
int main() {
std::cout << apply(10, doubler) << '\n';
return 0;
}実行時に選択する
関数ポインタは変数なので、プログラムの実行中に呼び出す関数を決定できます。
#include <iostream>
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int main() {
bool wantAdd = true;
int (*op)(int, int) = wantAdd ? add : sub;
std::cout << op(8, 3) << '\n';
return 0;
}関数ポインタの配列
複数の関数ポインタを配列に格納すると、値をインデックスとして使う単純なディスパッチテーブルを作成できます。
#include <iostream>
int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
int main() {
int (*ops[2])(int, int) = {add, mul};
std::cout << ops[0](2, 3) << ' ' << ops[1](2, 3) << '\n';
return 0;
}typedefを使用する
ポインタの構文は複雑です。typedefまたはusingのエイリアスを使うと、型に読みやすい名前を付けられます。
#include <iostream>
using BinOp = int(*)(int, int);
int add(int a, int b) { return a + b; }
int main() {
BinOp op = add;
std::cout << op(6, 7) << '\n';
return 0;
}アルゴリズムで関数ポインタを使用する
標準アルゴリズムは呼び出し可能オブジェクトを受け取れます。通常の関数もその1つとして使用できます。ここでは、述語で偶数を数えます。
#include <iostream>
#include <vector>
#include <algorithm>
bool isEven(int n) { return n % 2 == 0; }
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6};
int c = std::count_if(v.begin(), v.end(), isEven);
std::cout << "Evens: " << c << '\n';
return 0;
}制限事項: 状態を持てない
通常の関数ポインタは、キャプチャしたデータを保持できません。呼び出しの間でコンテキストを保持する必要がある場合は、グローバル変数を使うか、より高機能な呼び出し可能オブジェクトに移行する必要があります。
#include <iostream>
int counter = 0;
int next() { return ++counter; }
int main() {
int (*fn)() = next;
std::cout << fn() << ' ' << fn() << ' ' << fn() << '\n';
return 0;
}キャプチャなしラムダは変換される
何もキャプチャしないラムダは、一致する関数ポインタへ暗黙的に変換できます。小さなインライン関数に便利です。
#include <iostream>
int main() {
int (*fn)(int) = [](int x) { return x + 100; };
std::cout << fn(1) << '\n';
return 0;
}null関数ポインタ
関数ポインタにはnullptrを設定できます。これは何も指していないことを意味します。未定義動作を避けるため、呼び出す前に必ず確認してください。
#include <iostream>
int main() {
int (*fn)(int) = nullptr;
if (fn) {
std::cout << fn(5) << '\n';
} else {
std::cout << "No function set\n";
}
return 0;
}理解度チェック
関数ポインタの制限についての理解度を確認してください。
まとめ
関数ポインタについて学びました。
- 関数のアドレスを保持し、関数と同じように呼び出せます
- 動作をパラメーターとして渡したり、ディスパッチテーブルを作成したりできます
- エイリアスを使うと型を読みやすくできます
- 状態は保持できませんが、キャプチャなしラムダは関数ポインタに変換できます
次は、状態を持つものを含む任意の呼び出し可能オブジェクトを格納できるstd::functionを学びます。
よくある質問
「関数ポインタ」レッスンは無料ですか?
はい。「関数ポインタ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「関数ポインタ」で何を学びますか?
関数を引数として渡します ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「関数ポインタ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。