
Akim Demaille <akim <at> lrde.epita.fr> writes:
Le 7 oct. 2014 à 20:41, Joaquin M Lopez Munoz <joaquin <at> tid.es> a écrit :
A slightly smarter approach involves a cloning class that accepts a const Base& and does only clone on copy, thus avoiding dynamic memory allocation when the element already exists.
That's nice!
Ah, you should add a move ctor and assignment operator for better performance. Revised example: http://coliru.stacked-crooked.com/a/2ab8d00da3f71c84
Do you have any gut feeling about whether there should be only a single Exp-level hash-consing, or something with one flyweight per AST type (and conversions). I'm still considering both.
Do you mean having using ExpBin=poly_flyweight<Bin>; using ExpNum=poly_flyweight<Num>; rather than a single using ExpBin=poly_flyweight<Bin>? I think this is very hard to manage: to begin with, Bin has two Exp members, with this type splitting it is not even clear how you would manage the different cases where the operands to Bin are compound expressions or Num's (and the combinations thereof).
Is there anyway Flyweight could have supported the operator-> natively? It seems that with some SFINAE under the hood, it would work, don't you think?
Yep, that would be possible, the only reason I didn't do it is to not clutter the interface. Also, some std classes such as (C++17) std::optional implement operator* differently, without the extra dereference required by smart pointer semantics.
You lost me here, I have no idea what special trick in std::optional would prevent Flyweight from completing its forwarding to such operators.
It is a basic difference in indirection handling. Let me explain: std::optional<T> defines operator-> as optional<T> --> const T* which, for the case of optional<ptr<T>> (ptr being some pointer-like type), yields optional<ptr<T>> --> const ptr<T>* For instance: optional<T*> --> const T** With the interface you propose for flyweight, we'd have operator-> for flyweight<ptr<T>> defined as optional<ptr<T>> --> const T* So, there is a choice between having -> behave with "pointer semantics" (std::optional) or "pass-thru" semantics, for want of a better name. If we choose pass-thru semantics, then we're ruling out the possibility of having operator-> in instantiations such as, say, flyweight<int>, where the flyweight'd element is not a (smart) pointer. If I were to decided, I'd go for pointer semantics, which is more generally applicable. On the other hand, you can have your own poly_flyweight<T> class like the one shown with pointer semantics (because the intermediate pointer indirection is hidden in the implementation). Not sure I made myself clear :-) Joaquín M López Muñoz Telefónica