Skip to content

Latest commit

 

History

History
195 lines (155 loc) · 5.17 KB

228.md

File metadata and controls

195 lines (155 loc) · 5.17 KB
Info

Example

class foo {
 private:
  int data;
};

template<int foo::*Ptr>
int& get_data(foo& f) {
  return f.*Ptr;
}

template<int foo::*Ptr>
struct foo_access {
  friend int& get_data(foo& f) {
    return f.*Ptr;
  }
};

template struct foo_access<&foo::data>;
int& get_data(foo&);

int main() {
  foo f{};
  get_data(f) = 42; // access private data member
}

https://godbolt.org/z/65zee7exf

Puzzle

  • Can you implement get_token which gives access to the private trade token?
class trade {
 public:
  int price{};
  int size{};

  constexpr auto token() const { return token_; }

 private:
  std::string_view token_{};
};

 // TODO
std::string_view& get_token(trade&);

int main() {
  using namespace boost::ut;

  "access private token"_test = [] {
    trade t{};
    expect("" == t.token());
    get_token(t) = "Quantlab";
    expect("Quantlab" == t.token());
  };
}

https://godbolt.org/z/83dsMcErT

Solutions

class trade {
 friend std::string_view& get_token(trade&);

 public:
  int price{};
  int size{};

  constexpr auto token() const { return token_; }

 private:
  std::string_view token_{};
};

std::string_view& get_token(trade& t) {
    return t.token_;
}

https://godbolt.org/z/hvesa79n8

class trade {
 public:
  int price{};
  int size{};

  constexpr auto token() const { return token_; }

 private:
  std::string_view token_{};
};

template <std::string_view trade::*Ptr>
struct trade_access {
  friend auto get_token(trade& t) -> std::string_view& {
    return t.*Ptr;
  }
};

template struct trade_access<&trade::token_>;
auto get_token(trade& t) -> std::string_view&;

https://godbolt.org/z/37aerxdEs

template<class T, class V, V T::*Ptr, class Token>
struct BadFriend {
    friend V& get_data(T& f , Token const &  ) {
        return f.*Ptr;
    }
};
#define ACCESS( TYPE, MEMBER_TYPE, MEMBER )                              \
    struct MEMBER{                                                       \
        MEMBER( TYPE & t ):t(t){}                                        \
        auto & operator()();                                             \
        TYPE & t;                                                        \
    };                                                                   \
    template struct BadFriend<TYPE, MEMBER_TYPE, &TYPE::MEMBER, MEMBER>; \
    MEMBER_TYPE & get_data(TYPE&,MEMBER const & );                       \
    auto & MEMBER::operator()(){                                         \
        return get_data( t, *this );                                     \
    }

ACCESS(trade,std::string_view,token1_)
ACCESS(trade,std::string_view,token2_)

https://godbolt.org/z/7TdcE5zGf

namespace steal {
template <class>
struct trait;
template <class T, class U>
struct trait<T U::*> { using type = U; };
template<auto ptr, class tag>
struct member_pointer {
    friend constexpr auto& get_member_pointer(
        typename trait<decltype(ptr)>::type& f, const tag*) noexcept
    { return f.*ptr; }
};
}

// Must not be pasted inside any namespace
#define EXPOSE_MEMBER_AND_THEN_GO_THINK_ABOUT_WHAT_YOU_HAVE_DONE(NS, BASE, MEMBER) \
namespace NS {                                                                     \
class BASE##_##MEMBER {                                                            \
    BASE& base;                                                                    \
public:                                                                            \
    constexpr BASE##_##MEMBER(BASE& base) : base(base) {}                          \
    constexpr auto& operator()() const noexcept;                                   \
};                                                                                 \
}                                                                                  \
namespace steal {                                                                  \
template class member_pointer<&::NS::BASE::MEMBER, ::NS::BASE##_##MEMBER>;         \
constexpr auto& get_member_pointer(                                                \
    ::NS::BASE&, const ::NS::BASE##_##MEMBER*) noexcept;                           \
}                                                                                  \
constexpr auto& ::NS::BASE##_##MEMBER::operator()() const noexcept {               \
    return ::steal::get_member_pointer(base, this);                                \
}

namespace business::messages {
class trade {
public:
    int price{};
    int size{};

    constexpr auto token1() const { return token1_; }
    constexpr auto token2() const { return token2_; }
private:
    std::string_view token1_{};
    std::string_view token2_{};
};
}

EXPOSE_MEMBER_AND_THEN_GO_THINK_ABOUT_WHAT_YOU_HAVE_DONE(business::messages, trade, token1_)
EXPOSE_MEMBER_AND_THEN_GO_THINK_ABOUT_WHAT_YOU_HAVE_DONE(business::messages, trade, token2_)

https://godbolt.org/z/YWY4bv6dn