1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
#include <iostream>
#include <type_traits>
#include <functional>
#include <cstdio>
template <typename T> constexpr bool is_reference_wrapper_v = false; // TODO(mbozzi): stub
template<typename C, typename Pointed, typename T1, typename...Args >
constexpr decltype(auto) invoke_memptr(Pointed C::*f, T1&& t1, Args&&...args)
{
if constexpr (std::is_function_v<Pointed>)
{
if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
{
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
}
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
{
return (t1.get().*f)(std::forward<Args>(args)...);
}
else
{ // Typo fixed here, missing parentheses
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
}
}
else
{
static_assert(std::is_object_v<Pointed> && sizeof...(Args) == 0);
if constexpr (std::is_base_of_v<C, std::decay_t<T1>>)
{
return std::forward<T1>(t1).*f;
}
else if constexpr (is_reference_wrapper_v<std::decay_t<T1>>)
{
return t1.get().*f;
}
else
{
return (*std::forward<T1>(t1)).*f;
}
}
}
struct A1 { void f() {} };
struct A2 { void f() & {} };
struct T1
{
A1 a1;
A1& operator*() & noexcept { std::puts("A& operator*() & noexcept"); return a1; }
A1&& operator*() && noexcept { std::puts("A& operator*() && noexcept"); return std::move(a1); }
};
int main()
{
T1 t1;
invoke_memptr(&A1::f, t1);
invoke_memptr(&A1::f, T1{});
A2 a2;
invoke_memptr(&A2::f, a2);
// invoke_memptr(&A2::f, A2{}); // error, lvalue required
}
|