概要
やりたいこと:
C++ で, ポインタ変数で持っているインスタンスに対してメソッドを呼び出したい. 当然nullチェックが必要だが, メソッドがたくさんあるときに毎回チェックを書くのはだるい.
やったこと:
自分なりにいろいろとぐぐってみたがいまいちこれという解にたどり着けなくて, ためしに最近流行りのChatGPTさんに聞いてみたらほぼ期待通りの結果が得られてすごかった, という記録.
TL;DR
これが欲しかった関数.
#include <functional>
// ヘルパー関数定義
void callMethodIfValid(SomeClass* ptr, std::function<void(SomeClass*)> func) {
if (ptr != nullptr) {
func(ptr);
}
}
// 呼び出し例. ラムダ式で呼び出したい処理を渡す.
SomeClass* ptr;
callMethodIfValid(ptr, [](SomeClass* p) {
p->method1();
});
ChatGPT との Q&A
以下, 引用文はChatGPTへのクエリ, コードブロックはChatGPTからの返答である(コードに付随する説明文はばっさりと省略).
Q1. Nullチェックの基本処理
C++で, あるクラスのポインタ変数がnullptrならば無視し, 有効ならばメソッドを呼ぶ, という処理はどのように書けますか?
A1.
if (ptr != nullptr) {
ptr->method();
}
Nullチェックの基本.
Q2. Nullチェックを共通化したい
ptrにメソッドが大量に生えており, 確認のif文を大量にコピーしなければならないとすると, 重複を避けるうまい方法はありますか?
A2.
void callMethodIfValid(SomeClass* ptr) {
if (ptr != nullptr) {
ptr->method();
}
}
雰囲気はそれっぽいが, method()
が埋め込みなので意図とは異なる.
Q3. メソッド名を変数にしたい
呼びたいmethod()をcallMethodIfValid の外から指定したい場合, どのように書けばよいですか
A3.
#include <functional>
void callMethodIfValid(SomeClass* ptr, std::function<void(SomeClass*)> func) {
if (ptr != nullptr) {
func(ptr);
}
}
なるほど?
SomeClass* ptr = getPointer(); // ptrは、あるクラスのポインタ変数
callMethodIfValid(ptr, [](SomeClass* p) {
p->method1();
});
callMethodIfValid(ptr, [](SomeClass* p) {
p->method2();
});
これだあああすごいいい
応用など
教えてもらったコードを参考に, 外から変数をキャプチャしたりauto
で型名を省略したり.
int param;
callMethodIfValid(ptr, [param](auto* p) {
p->method1(param);
});
コード例は省略するが, メソッド呼び出しに成功したかどうかのbool
値を返すように変更するのも簡単.
ptr
をメンバに持つクラスを作ってそこに生やすのも良さそう.
あと今回自分の用途だと不要だったけど, メソッドの戻り値が欲しい場合はtemplate化してoptional
で受ければ良さそう.
#include <optional>
template <typename T>
std::optional<T> callMethodIfValid(SomeClass* ptr, std::function<T(SomeClass*)> func) {
if (ptr != nullptr) {
return func(ptr);
} else {
return std::nullopt;
}
};
…こうなってくると結局外でhas_value
とかが必要になってきちゃいそうだけど, でもメソッド呼び出しとは別のタイミングでチェックできると嬉しいケースもあるかもしれない(適当).
ChatGPTでは同一セッション中に前に出てきたワードを用いて対話ができるので, 意図とちょっと違う結果が返ってきても粘って話を続けると色々得られてすごい. 今後も活用していきたい.