WRT question #1:
constexpr
and inline
functions are the type-safe C++ equivalents of macro functions. They're not guaranteed to inline your code, but they give the compiler permission to make copies as needed, and an aggressive compiler will do the inlining for you. A lot of standard library classes make that assumption (e.g. std::vector<T>::size()
).
EDIT: Ok, you guys are viscious, but fair. Here's a way to use it to solve this problem:
EDIT: Updated to compile in C++14 as asked. I know this has been marked duplicate, and no one is going to look at it, but the other links are C++17 only. It also terminates on non-pointer members and returns a pointer to them, which is more in line with C#, which converts value types to Nullable.
#include <cstdio>
#include <type_traits>
template <typename Class>
struct SafePtrImpl {
Class* ptr;
SafePtrImpl(Class* ptr) : ptr(ptr) { }
template <typename TClass, typename TResult, std::enable_if_t<std::is_pointer<TResult>::value, std::nullptr_t> = nullptr>
inline SafePtrImpl<
std::remove_pointer_t<
std::remove_reference_t<
TResult>>> operator ->*(TResult TClass::*member) {
return SafePtr(ptr ? ptr->*member : nullptr);
}
template <typename TClass, typename TResult, std::enable_if_t<!std::is_pointer<TResult>::value, std::nullptr_t> = nullptr>
inline TResult* operator ->*(TResult TClass::*member) {
return ptr ? &(ptr->*member) : nullptr;
}
};
template <typename TClass>
SafePtrImpl<TClass> SafePtr(TClass* ptr) { return SafePtrImpl<TClass>(ptr); }
// --
struct Foo {
int x;
};
struct Bar {
Foo* y;
};
int main() {
Foo a { 42 };
Bar b { &a };
Bar c { nullptr };
Bar* d = nullptr;
int* b_y_x = SafePtr(&b)->*&Bar::y->*&Foo::x;
int* c_y_x = SafePtr(&c)->*&Bar::y->*&Foo::x;
int* d_y_x = SafePtr(d)->*&Bar::y->*&Foo::x;
printf("b: %08x %d\n", b_y_x, *b_y_x);
printf("c: %08x\n", c_y_x);
printf("d: %08x\n", d_y_x);
return 0;
}
https://godbolt.org/z/RYZ1EV
Output:
b: 3aa42aec 42
c: 00000000
d: 00000000