ControllerSender
is the base class, and several classes will be direct children of that (only BasicSender
is in this example) and instantiated through a factory function MidiControllers::AddSender
.
A pointer to the instantiated object, along with other information, is stored in a map. The sequence of building the information in the map is first to obtain the key (id) with AddController
and place a new member in the map with default Capabilities
. Then AddOutputPtr
places in Capabilities
for that key a shared_ptr
to the output device. Finally AddSender
creates a new sender for that key derived from ControllerSender
. It is this third step that is failing.
The factory function is throwing this compiler error:
binary '=': no operator found which takes a right-hand operand of type 'std::unique_ptr<BasicSender,std::default_delete<_Ty>>' (or there is no acceptable conversion) with [_Ty=BasicSender]
The failing line is
controllers_.at(id).sender_ = std::make_unique<BasicSender>(ptr);
If I change BasicSender
to the base class (ControllerSender
) the line compiles without error. I thought this assignment should automatically upcast the pointer, as explained in Is unique_ptr<Derived> to unique_ptr<Base> up-casting automatic?.
How do I fix this?
#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_;
};
unique_ptr<T>
to aunique_ptr<U>
whenT
derives fromU
. But that does requiresU
to have a virtual destructor. Your base classControllerSender
does not. Also, yourBasicSender
is using private inheritance instead of public inheritance, is that what you really want? – Remy Lebeau