I'm writing a class inheriting from std::unique_ptr for classes having a clone function:
template <typename T>
class cl_ptr : public std::unique_ptr<T>
{
public:
cl_ptr() noexcept = default;
cl_ptr(T* p) noexcept : std::unique_ptr<T>(p) {}
cl_ptr(cl_ptr<T> const& cp) : std::unique_ptr<T>(cp ? cp->clone() : nullptr) {}
cl_ptr(cl_ptr<T>&&) noexcept = default;
cl_ptr<T>& operator=(cl_ptr<T> const& cp) { this->reset(cp ? cp->clone() : nullptr); return *this; }
cl_ptr<T>& operator=(cl_ptr<T>&& cp) noexcept = default;
~cl_ptr() noexcept = default;
};
I have an error when I try to convert from an instance with type T to an instance with type T const:
cl_ptr<Foo> p1(new Foo);
cl_ptr<Foo const> p2 = p1; // <- Compiler error here
// error: conversion from ‘cl_ptr<Foo>’ to non-scalar type ‘cl_ptr<const Foo>’ requested
But I don't know how to implement it.
Of course I don't want that this code compiles:
cl_ptr<Foo const> p1(new Foo);
cl_ptr<Foo> p2 = p1; // <- Always wrong
Minimal reproductible example:
# include <memory>
template <typename T>
class cl_ptr : public std::unique_ptr<T>
{
public:
cl_ptr() noexcept = default;
cl_ptr(T* p) noexcept : std::unique_ptr<T>(p) {}
cl_ptr(cl_ptr<T> const& cp) : std::unique_ptr<T>(cp ? cp->clone() : nullptr) {}
cl_ptr(cl_ptr<T>&&) noexcept = default;
cl_ptr<T>& operator=(cl_ptr<T> const& cp) { this->reset(cp ? cp->clone() : nullptr); return *this; }
cl_ptr<T>& operator=(cl_ptr<T>&& cp) noexcept = default;
~cl_ptr() noexcept = default;
};
class Foo
{
public:
Foo() = default;
Foo(Foo const&) = default;
~Foo() noexcept = default;
Foo* clone() const { return new Foo(*this); }
};
int main()
{
cl_ptr<Foo> p1(new Foo);
cl_ptr<Foo const> p2 = p1;
cl_ptr<Foo> p3 = p2; // must fail
return 0;
}
I'm going to allow any conversion of
cl_ptr<T>tocl_ptr<U>where there is a conversion fromT *toU *, just likestd::unique_ptr. This allowsT *toconst T *and doesn't allowconst T *toT *, but also includesDerived *toBase *etc.