0

So recently I've been working on a library that is based around a hierarchy of classes as follows:

template <typename Base>
class Derived1 : public Base;

template <typename Base>
class Derived2 : public Base;

Fundamentally the problem I am trying to solve is given a common base class A I want a cheap (non-copying) conversion from a Derived1<A> to a Derived2<A>. Obviously this isn't going to work so well because any standard way of constructing a Derived2<A> from an A is going to involve a copy of the data in A - we can assume that this is a very expensive operation. The derived classes are essentially an interface for operating on the data contained in A

So the compromise I want to use is to create a proxy type for A, let's write Proxy<A>, which is a cheap object, so that I can convert a Derived<A> to a Derived2<Proxy<A>>. For example, if A = std::vector<int> then the proxy class I might use is a slice that just contains a pointer to the data and a size (or a pair of pointers, or iterators, whatever takes your fancy). (For simplicity let's assume that, once created, that the A never reallocates, which would invalidate my slices.) Now my Derived1<A> can implement a conversion operator to a Derived2<Slice<A>> and I have complete access to the data contained in A.

Now I want to play the same game with a std::map or std::unordered_map or some other kind of associative container type. The obvious choice of proxy type is, like the vector, a class that contains the begin and end iterators of the map. However, I have to re-implement the entire map interface on this proxy object. The other alternative is to have a proxy class that just contains a mutable reference to the container:

template <typename K, typename V>
class Proxy<std::map<K, V>>
{
    std::map<K, V>& map_ref;
}

This means I don't have to re-implement the interface but is deficient in other ways: for example, it cannot be default constructed (replacing reference with pointer slightly solves this problem, but still causes issues).

My question is: is there a sensible way to do this or some out of the box solution (in boost? I have looked but couldn't find such a thing.) I'm limited to C++14 but I welcome ideas that use c++17+ features for interest. I'm limited to C++14

SamM
  • 155
  • 1
  • 6
  • consider to use composition over inheritance. If `A` is a shared ptr member of `Derived1` and of `Derived2` then getting the conversion without copying the `A` is trivial – 463035818_is_not_an_ai Aug 08 '22 at 12:01
  • I am not a big fan of solving everything by inheritance (specially if it is only about code reuse and I agree with comment about composition). But I don't mind deriving from interfaces. Can both your object derive from the same abstract baseclass (interface)? Then you can create a map of (non-owning) interface pointers. And having that abstract baseclass will allow you to do some nice things for unit tests as well. – Pepijn Kramer Aug 08 '22 at 12:16
  • Apart from possible solutions mentioned above, you can also `std::move` your heavy stuff, you just need to impl good move constructor. – pptaszni Aug 08 '22 at 12:38
  • @pptaszni That also might be an option, but then the container gets to be the "owner" and I get the impression the container is more of a view on a specific aspect of the game objects (because of the "proxies"). but I could be wrong. – Pepijn Kramer Aug 08 '22 at 12:47
  • 1
    All this 'proxy' stuff sounds unnecessarily complicated to me. I'd go for composition - it seems like an ideal fit for this. – Paul Sanders Aug 08 '22 at 13:31
  • I'm trying to avoid pointer indirection and virtual functions wherever possible. Ultimately this needs to be something that I can port over to, for example CUDA. – SamM Aug 08 '22 at 14:11
  • I don't see the connection – Paul Sanders Aug 08 '22 at 16:23
  • The point is that I don't want to pay for an extra pointer indirection unless I absolutely have to – SamM Aug 08 '22 at 17:02

0 Answers0