Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run-time polymorphic class with value semantics

I would like a class Value, which both has a run-time polymorphic behaviour, and a value semantics. For instance, I would like to be able to do things like:

// create polymorphic data
Value v1 = IntValue(42);
Value v2 = DoubleValue(12.3);

// copy-by-value semantics
Value v3 = v1; 
v3.increments();
Value v4;
v4 = v2;
v4.increments();

// possibly put them in my favourite container
MyList<Value> l;
l << v1 << v2 << v3 << v4;

// print them: "Int(42) Double(12.0) Int(43) Double(13.0) "
for(int i=0; i<l.size(); i++) l[i].print();

Is it possible, and if yes, how?

Note: Using boost or C++11 smart pointers as here is not desired: they make the caller code verbose, use -> instead of ., and do not have copy constructors or assignment operators implementing a true value semantics. Also, this question doesn't target specifically containers.

like image 804
Boris Dalstein Avatar asked Apr 09 '26 18:04

Boris Dalstein


2 Answers

polymorphic_value has been proposed for standardisation and has some of the semantics you require. You'll have to define your own operator << though.

A polymorphic_value<T> may hold a an object of a class publicly derived from T, and copying the polymorphic_value will copy the object of the derived type.

polymorphic_value<T> is implemented with type erasure and uses the compiler-generated copy-constructor of the derived objects to correctly copy objects stored as polymorphic_value<BaseType>.

Copy constructors and assignment operators are defined so that the objects are value-like. There is no need to use or define a custom clone method.

In brief:

template <class T>
struct control_block 
{
  virtual ~control_block() = default;
  virtual T* ptr() = 0;
  virtual std::unique_ptr<control_block> clone() const = 0;
};

template <class T>
class polymorphic_value {
  std::unique_ptr<control_block<T>> cb_;
  T* ptr_ = nullptr;

 public:
  polymorphic_value() = default;

  polymorphic_value(const polymorphic_value& p) :
    cb_(p.cb_->clone())
  {
    ptr_ = cb_->ptr();
  }

  T* operator->() { return ptr_; }
  const T* operator->() const { return ptr_; }

  T& operator*() { return *ptr_; }
  const T& operator*() const { return *ptr_; }

  // Some methods omitted/deferred.
};

Specializations of the control block allow other constructors to be defined.

Motivation and design is discussed here :

https://github.com/jbcoe/polymorphic_value/blob/master/talks/2017_1_25_cxx_london.md

and here

https://github.com/jbcoe/polymorphic_value/blob/master/draft.md

A full implementation with tests can be found here:

https://github.com/jbcoe/polymorphic_value

like image 127
jbcoe Avatar answered Apr 11 '26 06:04

jbcoe


It's hard to know what you're trying to achieve here, but at first guess it seems that the (upcoming) Boost Type Erasure library might be suitable?

any<
    mpl::vector<
        copy_constructible<>,
        typeid_<>,
        incrementable<>,
        ostreamable<>
    >
> x(10);
++x;
std::cout << x << std::endl; // prints 11

(Example from docs).

like image 28
Alastair Avatar answered Apr 11 '26 08:04

Alastair



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!