In Modern C++ Design: Generic Programming and Design Patterns Applied
Andrei Alexandrescu advocates for making the policies' destructor protected:
Because the destructor is protected, only derived classes can destroy policy objects, so it's impossible for outsiders to apply delete to a pointer to a policy class. The destructor, however, is not virtual, so there is no size or speed overhead
But later, he writes the following paragraph on policy compatibility:
As you can see, you have two-sided flexibility in implementing conversions between policies. You can implement a conversion constructor on the left-hand side, or you can implement a conversion operator on the right-hand side.
Let's say we have 2 policies:
class First{
public:
First() = default;
First(const First&) = default;
protected:
~First() = default;
};
class Second{
public:
explicit operator First() const {
return //what???
}
Second() = default;
Second(const Second&) = default;
Second(const First& ) {};
protected:
~Second() = default;
};
How does one create a conversion operator from policy Second to policy First without constructing a temporary object of type First?
The problem is that you cannot create objects with protected destructors, except from a derived class. A conversion operator creating such temporaries is therefore forbidden. One way to get around it is to make
First
andSecond
accepts each other throughexplicit
constructors:You can then create a host class template
Host<Policy>
that has a templated conversion constructor that converts policiesPolicy
and arbitraryU
Live Example.
Note that protected destructors and public inheritance are indeed recommended, but they are especially recommended to safely use "enriched" (i.e. stateful) policies. For stateless policies, one can also use protected inheritance and public destructors. For those policies, conversion operators can generate temporaries just fine.