diff --git a/unit_test/util_gtest.cpp b/unit_test/util_gtest.cpp index b0b06919..66bcf3e1 100644 --- a/unit_test/util_gtest.cpp +++ b/unit_test/util_gtest.cpp @@ -166,6 +166,44 @@ TEST(utilTest, makeUnique) a[i] = i; } +TEST(utilTest, memberFn) +{ + struct Moo + { + int noParam() const & { return -2; } + + const int & twoParam(int & y, const int && z) && { return y += z; } + }; + + auto f = OEL_MEMBER_FN(noParam); + auto g = OEL_MEMBER_FN(twoParam); + + Moo const x{}; + EXPECT_EQ(-2, f(x)); + + auto y = 1; + EXPECT_EQ(3, g(Moo{}, y, 2)); + using T = decltype( g(Moo{}, y, 2) ); + static_assert(std::is_same_v); +} + +TEST(utilTest, memberVar) +{ + struct Baz + { + int val; + } x{7}; + + auto f = OEL_MEMBER_VAR(val); + + static_assert(std::is_same_v); + + using T = decltype( f(static_cast(x)) ); + static_assert(std::is_same_v); + + EXPECT_EQ(7, f(x)); +} + TEST(utilTest, toPointerContiguous) { using namespace oel; diff --git a/util.h b/util.h index cd730d8a..7830ad60 100644 --- a/util.h +++ b/util.h @@ -17,6 +17,21 @@ * @brief Contains make_unique_for_overwrite, as_signed/as_unsigned, index_valid, ssize and more */ + +/** @brief Take the name of a member function and wrap it in a stateless function object +* +* `wrapped(object, args)` becomes the same as `object.func(args)`. +* This macro works for function templates and overload sets, unlike std::mem_fn. +* Note that passing a function or pointer to member often optimizes worse. */ +#define OEL_MEMBER_FN(func) \ + [](auto && ob_, auto &&... args_) -> decltype(auto) \ + { return decltype(ob_)(ob_).func(decltype(args_)(args_)...); } + +//! Take the name of a member variable and wrap it in a stateless function object +#define OEL_MEMBER_VAR(var) \ + [](auto && ob_) noexcept -> auto && { return decltype(ob_)(ob_).var; } + + namespace oel {