Reputation: 3171
class Base {};
class Derived : public Base {};
void func(boost::optional<Base>&) {}
int main () {
boost::optional<Derived> x;
func(x);
}
will func accept both optionals: base and derived?
Upvotes: 4
Views: 867
Reputation: 5339
Even if it would work (which is likely buy I haven't checked) it would cause slicing. Only Base
part would be stored in optional.
optional keeps internally a buffer of the size needed to store Base
. And even if Base
would be of the same size as Derived
(as in your case) still it would store only Base
.
EDIT:
Above answer was given for the original question which contained following code:
int main () {
boost::optional x(Derived());
func(x);
}
Such code is not correct because of two reasons:
boost::optional
requires template argumentI have ignored those issues and assumed that something like this was meant:
int main () {
boost::optional<Base> x = Derived();
func(x);
}
While that code does compile (at least Visual Studio 2013 and Boost 1.60) and causes slicing. As can be seen by running following program:
#include <boost/optional.hpp>
#include <iostream>
class Base
{
public:
virtual ~Base() { std::cout << "~Base" << std::endl; }
};
class Derived : public Base
{
public:
virtual ~Derived() { std::cout << "~Derived" << std::endl; }
};
int main()
{
boost::optional<Base> x = Derived();
}
which produces output
~Derived ~Base ~Base
The second ~Base
shows that optional
destroyes Base
object rather than Derived
object. (The ~Derived
is from the temporary object Derived()
as is the first ~Base
.)
Upvotes: -1
Reputation: 303526
No, it won't work. func
takes an lvalue reference to boost::optional<Base>
. That means it can accept an lvalue of type boost::optional<Base>
, an lvalue of a type that derives publicly and unambiguously from boost::optional<Base>
, or some other type that has an operator boost::optional<Base>&()
. None of those is true of boost::optional<Derived>
. Class templates are not coviarant in the C++ type system - boost::optional<Derived>
does not inherit from boost::optional<Base>
.
It would be a different story if func
took its argument by value. If it looked like:
void func(boost::optional<Base> ) { }
In that case, you could call func
with a boost::optional<Derived>
. But that converting constructor is marked explicit
, so you would have to write:
func(boost::optional<Base>{x});
It's good that this is explicit - you are marking clear that you are (potentially) slicing x
.
Upvotes: 4