Почему в этом примере происходит автоматическое обновление с unique_ptr <derived>на unique_ptr <base>? - PullRequest
0 голосов
/ 11 ноября 2019

ControllerSender является базовым классом, и несколько классов будут прямыми потомками этого (только BasicSender в этом примере) и будут созданы с помощью фабричной функции MidiControllers::AddSender.

Указатель наэкземпляр объекта, наряду с другой информацией, хранится на карте. Последовательность построения информации на карте - сначала получить ключ (id) с AddController и поместить нового члена на карту с значением по умолчанию Capabilities. Затем AddOutputPtr помещает в Capabilities для этой клавиши shared_ptr для устройства вывода. Наконец, AddSender создает нового отправителя для этого ключа, полученного из ControllerSender. Это третий шаг, который завершается неудачей.

Заводская функция выдает эту ошибку компилятора:

binary '=': не найден оператор, который принимает правый операнд типа«станд :: unique_ptr> '(или нет приемлемого преобразования) с [_Ty = BasicSender]

Ошибка:

controllers_.at(id).sender_ = std::make_unique<BasicSender>(ptr);

Если я изменю BasicSender на базовый класс (ControllerSender) строка компилируется без ошибок. Я думал, что это назначение должно автоматически выгружать указатель, как объяснено в Является ли unique_ptr к unique_ptr автоматическим повышением частоты? .

Как мне это исправить?

#include <map>
#include <vector>
#include <JuceLibraryCode/JuceHeader.h>

class ControllerSender {
 public:
   ControllerSender(std::shared_ptr<juce::MidiOutput>& device) : device_(device) {}

 private:
   std::shared_ptr<juce::MidiOutput> device_{};
};

class BasicSender : ControllerSender {
 public:
   using ControllerSender::ControllerSender;
};

class MidiControllers {
 public:
   void AddController(const juce::MidiDeviceInfo& id)
   {
      controllers_.insert({id, Capabilities{}});
   }
   void AddOutputPtr(const juce::MidiDeviceInfo& id, std::shared_ptr<juce::MidiOutput>& device)
   {
      controllers_.at(id).device_ = device;
   }
   void AddSender(const juce::MidiDeviceInfo& id, std::string sender_name)
   {
      auto& ptr = controllers_.at(id).device_;
      if (ptr) {
         if (sender_name == "BasicSender") {
            controllers_.at(id).sender_ = std::make_unique<BasicSender>(ptr);
         }
      }
   }

 private:
   struct Capabilities {
      std::shared_ptr<juce::MidiOutput> device_{nullptr};
      std::unique_ptr<ControllerSender> sender_{nullptr};
   };

   struct IdentifierComp {
      bool operator()(const juce::MidiDeviceInfo& lhs, const juce::MidiDeviceInfo& rhs) const
          noexcept
      {
         return lhs.name < rhs.name || lhs.identifier < rhs.identifier;
      }
   };
   std::map<juce::MidiDeviceInfo, Capabilities, IdentifierComp> controllers_;
};

1 Ответ

4 голосов
/ 11 ноября 2019

Проблема в том, что вы использовали частное наследование:

class BasicSender : ControllerSender

, что означает отсутствие неявного преобразования из BasicSender * в ControllerSender * и, следовательно, неявное преобразование для соответствующих интеллектуальных указателей.

Чтобы исправить, используйте public:

class BasicSender : public ControllerSender

(или используйте struct ключевые слова вместо class, что означает, что доступ по умолчанию является общедоступным).

...