Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::optional abstract class type

I would like to have an optional object of an abstract type. However, boost::optional fails for abstract types:

#include <boost/optional.hpp>
class A { 
  virtual int getInt() = 0; 
};
class B : public A {
  int getInt() { return 666; };
};

int main() {
  boost::optional<A> maybeAnA;
  boost::optional<A> another(maybeAnA);
};

results in

error: invalid new-expression of abstract class type ‘A’

Just using a pointer doesn't seem a viable solution either, since some function needs to return an object containing the optional value as member, though it is not logical to expect the caller of the function to be the owner of that member variable.

like image 438
Tim Kuipers Avatar asked Jan 19 '15 10:01

Tim Kuipers


1 Answers

Optional has value semantics, so you cannot do what you want for the same reason that you cannot instantiate A itself:

A anA;

Because you seem to be interested in referring to an optional value, instead of owning/containing it:

You can have an optional containing a reference:

  • http://www.boost.org/doc/libs/1_57_0/libs/optional/doc/html/boost_optional/optional_references.html

This library allows the template parameter T to be of reference type: T&, and to some extent, T const&.

However, since references are not real objects some restrictions apply and some operations are not available in this case:

  • Converting constructors
  • Converting assignment
  • InPlace construction
  • InPlace assignment
  • Value-access via pointer

This way you can have exactly the same as when passing A&, but optional

Live On Coliru

#include <boost/optional.hpp>

struct A { 
  virtual int getInt() = 0; 
};

struct B : A {
  int getInt() { return 666; }
};

#include <iostream>

int main() {
  boost::optional<A&> maybeAnA;
  
  B b;
  maybeAnA = b; // non owning, just the reference
  
  boost::optional<A&> another(maybeAnA);
  
  std::cout << another->getInt();
}

Prints

666

If you /do/ want optional to act as a container of the type, you should indeed use unique_ptr<A> (it's already nullable, transferrable and owns the resource).

like image 88
sehe Avatar answered Nov 04 '22 19:11

sehe