Как вернуть умные указатели и ковариацию в C++

Я следую этому руководству, чтобы понять, как возвращать интеллектуальные указатели и ковариацию в C++.

  #include <memory>
  #include <iostream>

  class cloneable
  {
  public:
     virtual ~cloneable() {}

     std::unique_ptr<cloneable> clone() const
     {
        return std::unique_ptr<cloneable>(this->clone_impl());
     }

  private:
     virtual cloneable * clone_impl() const = 0;
  };
   
  ///////////////////////////////////////////////////////////////////////////////

  template <typename Derived, typename Base>
  class clone_inherit: public Base
  {
  public:
     std::unique_ptr<Derived> clone() const
     {
        return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
     }

  private:
     virtual clone_inherit * clone_impl() const override
     {
        return new Derived(*this); // getting error here 
     }
  };


  class concrete : public clone_inherit<concrete, cloneable>
  {
    
  };

  int main()
  {
    std::unique_ptr<concrete> c = std::make_unique<concrete>();
  }

Когда я выполняю этот пример, я получаю следующую ошибку:

  /tmp/0RmVdQYjfA.cpp: In instantiation of 'clone_inherit<Derived, Base>* clone_inherit<Derived, Base>::clone_impl() const [with Derived = concrete; Base = cloneable]':
  /tmp/0RmVdQYjfA.cpp:30:28:   required from here
  /tmp/0RmVdQYjfA.cpp:32:14: error: no matching function for call to 'concrete::concrete(const clone_inherit<concrete, cloneable>&)'
     32 |       return new Derived(*this);
        |              ^~~~~~~~~~~~~~~~~~
  /tmp/0RmVdQYjfA.cpp:37:7: note: candidate: 'constexpr concrete::concrete()'
     37 | class concrete : public clone_inherit<concrete, cloneable>
        |       ^~~~~~~~
  /tmp/0RmVdQYjfA.cpp:37:7: note:   candidate expects 0 arguments, 1 provided
  /tmp/0RmVdQYjfA.cpp:37:7: note: candidate: 'constexpr concrete::concrete(const concrete&)'
  /tmp/0RmVdQYjfA.cpp:37:7: note:   no known conversion for argument 1 from 'const clone_inherit<concrete, cloneable>' to 'const concrete&'
  /tmp/0RmVdQYjfA.cpp:37:7: note: candidate: 'constexpr concrete::concrete(concrete&&)'
  /tmp/0RmVdQYjfA.cpp:37:7: note:   no known conversion for argument 1 from 'const clone_inherit<concrete, cloneable>' to 'concrete&&'

Чтобы исправить эту ошибку в строке 32, мне пришлось вернуть именно указатель возврата на производный класс следующим образом:

  //   return  new static_cast<Derived*>(*this); to replace with 
  return new Derived(static_cast<const Derived&>(*this));

Может ли кто-нибудь предложить правильный способ исправить это?

@wohlstad спасибо, я исправил

GPrathap 18.07.2024 07:33

Вы застряли на C++17? это намного проще с явными аргументами объекта С++ 23

Caleth 18.07.2024 10:20

@Калет, можешь сказать это как ответ :) спасибо

GPrathap 21.07.2024 07:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете добавить частный неявный или явный оператор приведения:

template <typename Derived, typename Base>
class clone_inherit : public Base {
 public:
  std::unique_ptr<Derived> clone() const {
    return std::unique_ptr<Derived>(static_cast<Derived *>(this->clone_impl()));
  }

 private:
  // added here
  explicit operator const Derived &() const {
    return static_cast<const Derived &>(*this);
  }

  virtual clone_inherit *clone_impl() const override {
    return new Derived(*this);  // not getting error here
  }
};

Привет @3CxEZiVlQ, есть ли другие способы сделать это или это правильный способ сделать это?

GPrathap 18.07.2024 08:23

В любом случае спасибо

GPrathap 18.07.2024 08:23

Это спорно, как и весь код в вопросе, но не так уж и плохо.

3CxEZiVlQ 18.07.2024 08:26

Благодаря явным аргументам объекта C++ 23 этот шаблон становится очень простым:

class cloneable
{
public:
    template<typename Self>
    std::unique_ptr<Self> clone(this const Self& self) const {
        return std::make_unique<Self>(self);
    }
};

Это позволяет избежать необходимости указывать производный тип по мере его вывода.

спасибо, просто чтобы знать)

GPrathap 22.07.2024 18:05

Другие вопросы по теме

Похожие вопросы