190просмотров
10 мая 2025 г.
Score: 209
Если вы часто работаете с указателями в C++ и часто вызываете методы объекта по указателю, вам это может помочь. #include <functional>
#include <optional> template<typename T, typename Func, typename ...Args>
inline void safeCall(T obj, Func func, Args... args) { if (obj) { (obj->func)(args...); } else { }
} template<typename T, typename Func, typename ...Args>
inline void safeCall(T obj, Func func, Args... args, std::function<void()> onNull) { if (obj) { (obj->func)(args...); } else { onNull(); }
} template<typename T, typename R, typename Func, typename ...Args>
inline std::optional<R> safeCallVal(T obj, Func func, Args ...args) { if (obj) { return (obj->func)(args...); } else { return std::nullopt; }
} Как это работает?
Функция проверяет, является ли указатель нулевым.
Если нет, вызывается метод из объекта, а если да, то выполнить onNull или ничего не делать (зависит от выбранной перегрузки функции). Вам не нужно открывать блок if, чтобы проверить объект на nullptr/NULL. Мне кажется, что это удобно, когда много указателей на объекты и из них часто нужно вызывать методы. Пример:
#include <iostream>
#include <string> // .... Код функций выше class CExample {
public: void Output() { std::cout << "Hello" << std::endl; } int Add(int a, int b) { return 42; }
}; int main() { CExample* pExample = nullptr; // Now it's time for test safeCall(pExample, &CExample::Output, {std::cout << "Failed to call Output from CExample." << std::endl; }); auto result = safeCallVal<CExample, int>(pExample, &CExample::Add, 42, 255); std::cout << "The result is " << (result.has_value() ? std::to_string(result.value()) : "None") << std::endl; return 0;
} Может быть это всё таки кому-то покажется странным или даже не удобным, но мне иногда просто лень писать
if (obj) {
<code>
}
else {
<othercode>
}
, как минимум потому, что такие блоки обычно пишутся в несколько строчек. А вы как думаете?