2

P0847 proposes the possibility of using explicit this parameter for member functions.

Among other great goodies that this proposal brings, there is also the great new possibility for CRTP without C, R and even T.

A common practice for implementing a generic clone in C++ is based on CRTP, see for example this SO post.

Given that we need clone to be virtual (or at least, behave as virtual), to allow:

Shape* pCopy = pShape->clone(); // get a copy of the correct runtime type

And given that the proposal is that a member function with an explicit this parameter shall not be declared virtual.

Would there still be a way to use P0847 in order to implement a generic clone with dynamic behavior and without CRTP?

Amir Kirsh
  • 12,564
  • 41
  • 74
  • 2
    Maybe a bit early to create that tag, no? :p – cigien Oct 29 '20 at 18:54
  • 1
    @cigien the tag would be needed at a certain point of time, now or later – Amir Kirsh Oct 29 '20 at 18:55
  • 3
    Unless it comes out as `c++24`. For now... `c++2b`? – Eljay Oct 29 '20 at 18:56
  • 1
    Yeah, I'm inclined to go with @Eljay on that. No big deal I suppose. The tag name can be retroactively changed if needed, I think. – cigien Oct 29 '20 at 18:56
  • After looking at P0847 5.2.1, I think the answer to your question is **yes**, a "generic" clone could leverage this language feature to do a `clone`. And the resulting code would be a lot more straightforward (for those of use who find CRTP turns our brains into a klein bottle pretzel). – Eljay Oct 29 '20 at 19:38
  • @Eijay after reading Jarod's answer and thinking about it again I tend to agree that the answer is **no**, as P0847 can assist with deducing **the static type of `this`** but **not the dynamic type**. It means that a dynamic clone would still require either virtual function in each derived class or the fully fledged CRTP with the C, R and T. In cases where CRTP is used for deducing static type, P0847 would allow to replace CRTP with a templated method having an explicit this parameter, as presented in the paper. – Amir Kirsh Oct 30 '20 at 08:55
  • I wish I had a compiler that had P0847 implemented so I could play with it. Drat! – Eljay Oct 30 '20 at 17:56

2 Answers2

5

template deduction only uses static type, whereas Clone need dynamic type, and so virtual.

P0847 mostly allows to transform

template <typename T>
T* Foo(const T& obj);
// With Obj base of T

into

template <typename Self>
Self* Obj::Foo(this const Self& obj);

What you could do though is simplify the covariance with smart pointer.

struct Clonable
{
    virtual ~Clonable() = default;
    virtual Clonable* do_clone() const = 0;

    template <typename Self>
    std::unique_ptr<Self> clone(this const Self& self)
    {
        std::unique_ptr<Self>(self.do_clone());
    }
};

struct MyClass : Clonable
{
    MyClass* do_clone() const override { return new MyClass(*this); }
};

But CRTP seems better as it allows to avoid to rewrite do_clone for each type.

(future reflection might simplify Clonable)

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

It is unclear if this proposal permits an explicit this on a constructor.

If it did we could solves this.

struct clonable {
  icloneable const*(*do_clone)(icloneable const*) = 0;
  template<class Derived>
  clonable( this Derived& ):
    do_clone([](icloneable const* vself)->icloneable const*{
      return new Derived(*static_cast<Derived const*>(vself);
    })
  {}
  icloneable const* clone() const {
    return do_clone( this );
  }
};

this relies on the ability to have explicit this passed to constructors, and that explicit this parameter being the most-derived type.

We basically implemented a vtable (of one entry) ourselves.

Failing the ability to do this, you might have to wait for reflection.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524