How to write constructors for implicit conversions from instances of a templated class C<Derived> to instances of C<Base>

huangapple go评论69阅读模式
英文:

How to write constructors for implicit conversions from instances of a templated class C<Derived> to instances of C<Base>

问题

I have created a template class derived from shared_ptr<const T> that enables a holder of the shared pointer to modify the pointed instance by cloning the instance and resetting the shared_pointer. (T can be a clonable class or a class that has a copy constructor, hence the weird double definition of the modify method)

shared_ptr<Base> can be implicitly constructed/copied by an instance of class shared_ptr<Derived>. But my class cannot.

How can I make that possible? I suppose I need to create a templated constructor that accepts an argument of type const_shared_ptr<D> where D is a type derived from the template type C. I don't know how to write that. I guess it is possible as shared_ptr can do it.

template <typename T, typename = int>
struct HasPolymorphicClonage : std::false_type { };
template <typename T>
struct HasPolymorphicClonage <T, decltype(&T::clone, 0)> : std::true_type { };

template<typename C>
class shared_const_ptr : public std::shared_ptr<const C>
{
public :
    shared_const_ptr(const C * c) : std::shared_ptr<const C>(c) {}
    shared_const_ptr() = default;

    // Definition of the modify method depending on whether T offers a clone method or not
    template<typename T1 = C>
    typename std::enable_if_t<HasPolymorphicClonage<T1>::value, C&> modify()
    {
        C * replacement = (*this)->clone();
        this->std::shared_ptr<const C>::reset(replacement);
        return *replacement;
    }

    template<typename T1 = C>
    typename std::enable_if_t<!HasPolymorphicClonage<T1>::value, C&> modify()
    {
        C * replacement = new C(**this); // Using the copy constructor
        this->std::shared_ptr<const C>::reset(replacement);
        return *replacement;
    }
};

(Note: I have translated the provided code into English, but I have not modified the code itself.)

英文:

I have created a template class derived from shared_ptr&lt;const T&gt; that enables a holder of the shared pointer to modify the pointed instance by cloning the instance and reseting the shared_pointer. (T can be a clonable class or a class that have a copy constructor whence the weird double definition of the modify method)

shared_ptr&lt;Base&gt; can be implicitly constructed/copied by a instance of class shared_ptr&lt;Derived&gt;. But my class cannot.

How can I make that possible? I suppose I need to create a templated constructor that accepts argument of type const_shared_ptr&lt;D&gt; where D is a type derived from the template type C. I don't know how to write that. I guess it is possible as shared_ptr can do it.

template &lt;typename T, typename = int&gt;
struct HasPolymorphicClonage : std::false_type { };
template &lt;typename T&gt;
struct HasPolymorphicClonage &lt;T, decltype(&amp;T::clone, 0)&gt; : std::true_type { };

template&lt;typename C&gt;
class shared_const_ptr : public std::shared_ptr&lt;const C&gt;
{
public :
    shared_const_ptr(const C * c) : std::shared_ptr&lt;const C&gt;(c) {}
    shared_const_ptr() =default;

    // d&#233;finition de la m&#233;thode modify selon que T propose ou non une m&#233;thode clone
    template&lt;typename T1 = C&gt;
    typename std::enable_if_t&lt;HasPolymorphicClonage&lt;T1&gt;::value,C&amp;&gt; modify()
    {
        C * remplacant = (*this)-&gt;clone();
        this-&gt;std::shared_ptr&lt;const C&gt;::reset(remplacant);
        return *remplacant;
    }

    template&lt;typename T1 = C&gt;
    typename std::enable_if_t&lt;!HasPolymorphicClonage&lt;T1&gt;::value,C&amp;&gt; modify()
    {
        C * remplacant = new C(**this); // on utilise le constructeur par recopie
        this-&gt;std::shared_ptr&lt;const C&gt;::reset(remplacant);
        return *remplacant;
    }

};

答案1

得分: 1

添加一个接受 std::shared_ptr&lt;T&gt; 的模板构造函数应该可以工作:

template&lt;typename C&gt;
class shared_const_ptr : public std::shared_ptr&lt;const C&gt;
{
public:
    // ...

    template &lt;typename T&gt;
    shared_const_ptr(std::shared_ptr&lt;const T&gt; const&amp; other) : std::shared_ptr&lt;const C&gt;(other) {}

};

struct Base {};
struct Derived : Base {};

int main()
{
    shared_const_ptr&lt;Base&gt; b;
    shared_const_ptr d(new Derived{});
    b = d;
}

当从 d 构造 b 时,参数转换会将 d 转换为 std::shared_ptr&lt;const Derived&gt;。这个构造函数是可行的,因为 std::shared_ptr&lt;const Derived&gt; 可以转换为 std::shared_ptr&lt;const Base&gt;

英文:

Adding a templated constructor accepting a std::shared_ptr&lt;T&gt; should work:

template&lt;typename C&gt;
class shared_const_ptr : public std::shared_ptr&lt;const C&gt;
{
public :
    // ...

    template &lt;typename T&gt;
    shared_const_ptr(std::shared_ptr&lt;const T&gt; const&amp; other) : std::shared_ptr&lt;const C&gt;(other) {}

};

struct Base {};
struct Derived : Base {};

int main()
{
    shared_const_ptr&lt;Base&gt; b;
    shared_const_ptr d(new Derived{});
    b = d;
}

https://godbolt.org/z/n45PKE9ff

When constructing b fromd, argument conversion will convert d to a std::shared_ptr&lt;const Derived&gt;. The constructor is viable because std::shared_ptr&lt;const Derived&gt; is convertible to std::shared_ptr&lt;const Base&gt;.

huangapple
  • 本文由 发表于 2023年4月19日 18:56:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76053679.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定