Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Covariance and xxx_ptr

155 views
Skip to first unread message

Javier

unread,
Mar 5, 2016, 8:10:09 AM3/5/16
to
{ edited to shorten lines to ~70 characters (except code). -mod }

Consider:

struct Consumer {
virtual Provider* use();
};

struct ConcreteConsumer {
ConcreteProvider* use() override {...}
};

struct Provider {...};
struct ConcreteProvider : public Provider {...}

The covariant return type is just fine, thank you very much. However, if
I want to create something like:

struct Consumer {
virtual unique_ptr<Provider> use();
};

struct ConcreteConsumer {
unique_ptr<ConcreteProvider> use() override {...}
};

struct Provider {...};
struct ConcreteProvider : public Provider {...}

Cannot be done. I understand the reason, but it seems to me unintuitive
that covariance does not "port" when using any of the std::xxx_ptr
types.
Furthermore, a corresponding implementation for ConcreteConsumer would
have to look like this to type derived from Provider:

struct ConcreteConsumer {
unique_ptr<Provider> use() override { return
unique_ptr<Provider>{make_unique<ConcreteProvider>();}
};


In essence, I think that std::is_convertible<xxx_ptr<Derived>,
xxx_ptr<Base>>should succeed in the same way that
std::is_convertible<Derived*, Base*> succeeds, and overriding a member
function that returns xxx_ptr where the types are covariant should be
allowed.

Are there technical limitations? Seems to me that no abstractions would
be broken.

Regards,
--Javier


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Öö Tiib

unread,
Mar 7, 2016, 1:20:11 PM3/7/16
to

On Saturday, 5 March 2016 15:10:09 UTC+2, Javier wrote:
>
> The covariant return type is just fine, thank you very much. However, if
> I want to create something like:
>
> struct Consumer {
> virtual unique_ptr<Provider> use();
> };
>
> struct ConcreteConsumer {
> unique_ptr<ConcreteProvider> use() override {...}
> };
>
> struct Provider {...};
> struct ConcreteProvider : public Provider {...}
>
> Cannot be done. I understand the reason, but it seems to me unintuitive
> that covariance does not "port" when using any of the std::xxx_ptr
> types.

In some other context also covariance of 'vector<Provider>' and
'vector<ConcreteProvider>' (or iterators to such) may feel like
intuitively making sense.

Simulation of covariance (where it makes sense) can be made manually
by using private virtual 'doUse()' and public non-virtual 'use()' that calls
'doUse()' and converts its return type. The 3-4 additional lines per class
are not that much if you need it and if you don't need it then YAGNI.

> Furthermore, a corresponding implementation for ConcreteConsumer would
> have to look like this to type derived from Provider:
>
> struct ConcreteConsumer {
> unique_ptr<Provider> use() override { return
> unique_ptr<Provider>{make_unique<ConcreteProvider>();}
> };
>
>
> In essence, I think that std::is_convertible<xxx_ptr<Derived>,
> xxx_ptr<Base>>should succeed in the same way that
> std::is_convertible<Derived*, Base*> succeeds, and overriding a member
> function that returns xxx_ptr where the types are covariant should be
> allowed.

The inbuilt covariance is only for raw pointers and references and there are
no covariance of class type objects (that smart pointers are). Covariance is
about inheritance and not about convertibility but converting objects of
derived class into object of base class means object slicing so it has to be
a pointer or reference.

Smart pointers indeed manage to simulate covariance somewhat with
conversion assignment templates and conversion constructor templates
in order to be more similar to raw pointers.

>
> Are there technical limitations? Seems to me that no abstractions would
> be broken.

Turning all implicit convertibility into covariance is likely bad idea.
Implicit convertibility often confuses programmers and it does not
need to have more ways of application. Adding some "magic"
specially to smart pointers is likely even worse since these would
then be core language features that only look like library classes.
0 new messages