Skip to content

Instantly share code, notes, and snippets.

@tomilov
Created May 13, 2024 19:39
Show Gist options
  • Select an option

  • Save tomilov/56d3ed80413b45ddae0583e6bb224efc to your computer and use it in GitHub Desktop.

Select an option

Save tomilov/56d3ed80413b45ddae0583e6bb224efc to your computer and use it in GitHub Desktop.
#include <type_traits>
#include <utility>
// FOR_EACH from https://www.scs.stanford.edu/~dm/blog/va-opt.html
#define PARENS ()
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
#define EXPAND1(...) __VA_ARGS__
#define FOR_EACH(macro, ...) \
__VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
#define FOR_EACH_HELPER(macro, a1, ...) \
macro(a1) \
__VA_OPT__(FOR_EACH_AGAIN PARENS (macro, __VA_ARGS__))
#define FOR_EACH_AGAIN() FOR_EACH_HELPER
#define MEMBER_ACCESS(member) , \
[](auto* clazz) constexpr -> auto* \
{ \
if constexpr (std::is_pointer_v<std::remove_reference_t<decltype(clazz->member)>>) { \
return clazz ? clazz->member : nullptr; \
} else { \
return clazz ? &clazz->member : nullptr; \
} \
}
template<typename Prev, typename Curr, typename... Next>
constexpr auto* compose(Prev* prev, Curr&& curr, Next&&... next)
{
auto* clazz = curr(prev);
if constexpr (sizeof...(next) == 0) {
return clazz;
} else {
return compose(clazz, std::forward<Next>(next)...);
}
}
#define OPT_DEREF(first, ...) \
compose(&first FOR_EACH(MEMBER_ACCESS, __VA_ARGS__))
#include <memory>
#include <optional>
#include <cassert>
int main()
{
{
struct Z { int t = 123; };
struct Y { Z z; };
struct X { Y y; } x;
int * t = OPT_DEREF(x, y, z, t);
assert(&x.y.z.t == t);
}
{
int t = 123;
struct Z { int * t = nullptr; } z{&t};
struct Y { Z * z = nullptr; } y{&z};
struct X { Y * y = nullptr; } x{&y};
int * pt = OPT_DEREF(x, y, z, t);
assert(&t == pt);
}
{
int t = 123;
struct Z { int * t = nullptr; } z{&t};
struct Y { Z * z = nullptr; } y{};
struct X { Y * y = nullptr; } x{&y};
int * pt = OPT_DEREF(x, y, z, t);
assert(!pt);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment