1

I have this multiset container:

multiset<IMidiMsgExt, IMidiMsgExtComp> queuedNotes;

IMidiMsgExt is a struct I've created myself (I need it for one additional property, mTick) that extend IMidiMsg :

struct IMidiMsgExt : public IMidiMsg
{
    IMidiMsgExt() {
    }

    double mTick = 0.;

    void IMidiMsgExt::MakeNoteOnMsg(int noteNumber, int velocity, int offset, double tick, int channel)
    {
        Clear();
        mStatus = channel | (kNoteOn << 4);
        mData1 = noteNumber;
        mData2 = velocity;
        mOffset = offset;
        mTick = tick;
    }

    void IMidiMsgExt::MakeNoteOffMsg(int noteNumber, int offset, double tick, int channel)
    {
        Clear();
        mStatus = channel | (kNoteOff << 4);
        mData1 = noteNumber;
        mOffset = offset;
        mTick = tick;
    }

    void IMidiMsgExt::Clear()
    {
        mOffset = 0;
        mStatus = mData1 = mData2 = 0;
        mTick = 0.;
    }
};

Next: I store in that queuedNotes multiset some IMidiMsgExt objects, with:

IMidiMsgExt* noteOff = new IMidiMsgExt;
noteOff->MakeNoteOffMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(*noteOff);

Now, I need to use a function called SendMidiMsg(IMidiMsg* pMsg) (that takes IMidiMsg type as input) sending my object IMidiMsgExt to it.

I extract the first object from my list to an iterator:

auto midiMessage = queuedNotes.begin();

But when I try to cast it and use SendMidiMsg:

SendMidiMsg((IMidiMsgExt*)midiMessage);

it says no suitable conversion function from "std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<IMidiMsgExt>>>" to "IMidiMsg *" exists

Where am I wrong? Should I use dynamic casting?

markzzz
  • 47,390
  • 120
  • 299
  • 507

1 Answers1

4
auto midiMessage = queuedNotes.begin();

midiMessage is of type std::multiset::iterator. And it is not convertable to your type IMidiMsgExt. Iterator is an object that behaves similarly to a pointer, so you can use dereference operator (*) to get the object that it "points to". You also don't need to cast derived object to its base, that is done implicitly. All you need to do is get the address of where the iterator "points to" to get a pointer to IMidiMsgExt:

SendMidiMsg(&*midiMessage);

A quick break down of &*midiMessage:

  variable    -     type
midiMessage   - std::multiset::iterator
*midiMessage  - IMidiMsgExt
&*midiMessage - IMidiMsgExt*

Edit: About your const_iterator error. std::multiset::begin() is supposed to always return const_iterator. Your function SendMidiMsg() wants a non const pointer - it is saying it wants to edit the message. multiset does not allow changing the elements.

You can copy the message and then call SendMidiMsg(). If you don't need the message inside the container anymore, you can also erase it afterwards.

auto msg = *midiMessage;
SendMidiMsg(&msg);
queuedNotes.erase(midiMessage);

Note: It seems like you have a memory leak in the program. You create messages with new and I don't see any calls to delete, to release the memory.

IMidiMsgExt* noteOff = new IMidiMsgExt;
noteOff->MakeNoteOffMsg(57, 0, tickSize * 111, 0);
queuedNotes.insert(*noteOff);
Community
  • 1
  • 1
rozina
  • 4,120
  • 27
  • 49
  • But it says: `argument of type "const IMidiMsgExt *" is incompatible with parameter of type "IMidiMsg *"` – markzzz Apr 21 '16 at 10:02
  • @paizza That meas that `queuedNotes.begin()` returns a `const_iterator`. If you dereference a `const_iterator` it returns a const reference to the object. Your `SendMidiMsg()` expect a non const pointer. You have a conceptual error in your progrem. You are trying to modify something you said should not be modified. – rozina Apr 21 '16 at 10:06
  • I can't change `SendMidiMsg()`, since it's a method within the Framework I'll use. The only way is to change the `iterator` returning type. But also there: I cannot edit `multiset` list. Should I need to change container? Somethings that store and return a non-const element? – markzzz Apr 21 '16 at 10:09
  • No. The question is why do you get a `const_iterator`. You must have a const reference to `queuedNotes`. It would help if you show the code before you call `SendMidiMsg()`. The ineresting bit is where do you get `queuedNotes` from before you call `begin()` on it. – rozina Apr 21 '16 at 10:12
  • Before `begin` I just check this: `while (queuedNotes.size() > 0)`. Than auto and that function. I decleare `multiset queuedNotes;` within a .h file. – markzzz Apr 21 '16 at 10:15
  • And I use this `comparator` struct IMidiMsgExtComp { bool operator()(const IMidiMsgExt& lhs, const IMidiMsgExt& rhs) { return lhs.mTick < rhs.mTick; } }; – markzzz Apr 21 '16 at 10:15
  • On comparator there is `const`. That would be the problem? – markzzz Apr 21 '16 at 10:16
  • I don't think! If I remove const in the method, nothing change! It's all the same. – markzzz Apr 21 '16 at 10:17
  • Which other code would you like to see? I don't have any. after `multiset queuedNotes;` I just insert object with `.insert(*noteOff)` as stated in the question. – markzzz Apr 21 '16 at 10:30
  • @paizza Hm very strange. Try using the type instead of auto like: `std::multiset::iterator midiMessage = queuedNotes.begin();` If this doesn't work then I don't know. `begin()` should return an `iterator` and not a `const_iterator` if `queuedNotes` is not const qualified. – rozina Apr 21 '16 at 10:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109797/discussion-between-paizza-and-rozina). – markzzz Apr 21 '16 at 10:53