Skip to content

Instantly share code, notes, and snippets.

@Liam0205
Last active October 11, 2020 14:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Liam0205/463702b282d1f102b6ccb56bb9f0a82e to your computer and use it in GitHub Desktop.
Save Liam0205/463702b282d1f102b6ccb56bb9f0a82e to your computer and use it in GitHub Desktop.
Implementation of `operator->*` for `std::shared_ptr`
#include <iostream>
#include <functional>
#include <type_traits>
#include <cstddef>
#include <utility>
#include <memory>
namespace yuuki {
template<size_t> // begin with 0 here!
struct placeholder_template
{};
} // namespace yuuki
namespace std {
template<size_t N>
struct is_placeholder<yuuki::placeholder_template<N>>
: integral_constant<int, N + 1> // the one is important
{};
} // namespace std
namespace yuuki {
template <typename Ret, typename... Args, size_t... Is>
decltype(auto) bind(Ret (*p)(Args...), std::index_sequence<Is...>) {
static_assert(sizeof...(Args) == sizeof...(Is));
return std::bind(p, placeholder_template<Is>{}...);
}
template <typename Ret, typename... Args, typename... Given, size_t... Is>
decltype(auto) bind(Ret (*p)(Args...), std::index_sequence<Is...>, Given... g) {
static_assert(sizeof...(Args) == sizeof...(Given) + sizeof...(Is));
return std::bind(p, std::forward<Given>(g)..., placeholder_template<Is>{}...);
}
template <typename Ret, typename... Args, typename... Given>
decltype(auto) bind(Ret (*p)(Args...), Given... g) {
constexpr size_t num_placeholders = sizeof...(Args) - sizeof...(Given);
if constexpr (sizeof...(Given) == 0) {
return yuuki::bind(p, std::make_index_sequence<num_placeholders>{});
} else {
return yuuki::bind(p, std::make_index_sequence<num_placeholders>{}, std::forward<Given>(g)...);
}
}
template <typename T, typename Ret, typename... Args>
decltype(auto) pmf_conversion(Ret(T::*p)(Args...)) {
return reinterpret_cast<Ret(*)(T*, Args...)>(p);
}
template <typename T, typename Ret, typename... Args>
decltype(auto) pmf_conversion(Ret(T::*p)(Args...) const) {
return reinterpret_cast<Ret(*)(const T*, Args...)>(p);
}
} // namespace yuuki
template <typename T, typename MemberT>
decltype(auto) operator->*(std::shared_ptr<T> ptr, MemberT mem) {
if constexpr (std::is_member_function_pointer_v<MemberT>) {
return yuuki::bind(yuuki::pmf_conversion(mem), ptr.get());
} else {
return ptr.get()->*mem;
}
}
struct Foo {
void bar(double) {
std::cerr << "You're calling " << __PRETTY_FUNCTION__ << "\n";
}
void qux() const {
std::cerr << "You're calling " << __PRETTY_FUNCTION__ << "\n";
}
int baz = 42;
};
void bazz() {
std::cerr << "You're calling " << __PRETTY_FUNCTION__ << "\n";
}
int main() {
yuuki::bind(bazz)();
auto smartp = std::make_shared<Foo>();
auto rawp = smartp.get();
auto funcp = &Foo::bar;
auto memp = &Foo::baz;
(rawp->*funcp)(0.0);
(smartp->*funcp)(0.0);
((*rawp).*funcp)(0.0);
((*smartp).*funcp)(0.0);
std::cerr << "Accessing data member by member-pointer: " << (rawp->*memp) << '\n';
std::cerr << "Accessing data member by member-pointer: " << (smartp->*memp) << '\n';
std::cerr << "Accessing data member by member-pointer: " << ((*rawp).*memp) << '\n';
std::cerr << "Accessing data member by member-pointer: " << ((*smartp).*memp) << '\n';
// smartp->qux();
auto funcq = &Foo::qux;
yuuki::pmf_conversion(funcq)(rawp);
(rawp->*funcq)();
(smartp->*funcq)();
((*rawp).*funcq)();
((*smartp).*funcq)();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment