I have declared this STL multiset
:
multiset playingNotes;
and my comparator is:
Use std::find_if.
int value = 60;
auto iteratorItemFound = std::find_if(std::begin(playingNotes), std::end(playingNotes), [value](const IMidiMsgExt& msg)
{
return msg.mNote == value;
});
I'd agree with Mohamad Elghawi's answer. But it is incomplete.
Your actual code will use a find_if, just like this:
const auto it = find_if(cbegin(playingNotes), cend(playingNotes), [value = int{60}](const auto& i){return i.mNote == value;});
if(it != cend(playingNotes)) {
playingNotes.erase(it);
}
This will remove the IMidiMsgExt
with the lowest mTick
value which has an mNote
of 60 (or whatever value
was initialized to.) If there are multiple IMidiMsgExt
s in playingNotes
that tie for the lowest, the IMidiMsgExt
that has been in playingNotes
the longest will be removed.
You're explanation of the problem was a little sparse, so I've created and solved a Minimal, Complete, Verifiable Example here: http://ideone.com/oFQ4rS
What you want to do is not possible (while keeping the logarithmic search properties of the map). The reason is that the find
method takes an instance of key_type
, so even writing a custom comparator which has overloads for comparing your key_type against ints will not work.
The idea of a key_type
is that it's an immutable and cheap object to construct - i.e. you should be unafraid to treat it as a value that can be copied.
Edit:
Here's how I may approach it.
Synopsis:
code:
#include <vector>
#include <algorithm>
struct midi_message
{
midi_message(int timestamp, int note)
: _timestamp(timestamp)
, _note(note)
{}
int timestamp() const { return _timestamp; }
int note() const { return _note; }
private:
int _timestamp, _note;
};
struct earlier
{
bool operator()(const midi_message& l, const midi_message& r) const {
return l.timestamp() < r.timestamp();
}
bool operator()(const midi_message& l, const int& r) const {
return l.timestamp() < r;
}
};
struct midi_messages
{
// insert messages, keeping the map sorted by timestamp
void add(midi_message m) {
auto i = std::lower_bound(std::begin(_data),
std::end(_data),
m.timestamp(),
earlier());
_data.insert(i, std::move(m));
}
bool remove_first_note_like(int note)
{
auto i = std::find_if(std::begin(_data),
std::end(_data),
[note](auto& msg)
{ return msg.note() == note; });
if (i != std::end(_data)) {
_data.erase(i);
return true;
}
return false;
}
std::size_t remove_all_before(int timestamp)
{
auto new_begin = std::lower_bound(std::begin(_data),
std::end(_data),
timestamp,
[](auto& msg, auto& timestamp) {
return msg.timestamp() < timestamp;
});
_data.erase(std::begin(_data), new_begin);
}
private:
std::vector<midi_message> _data;
};
int main()
{
midi_messages messages;
messages.add(midi_message(1000, 60));
messages.add(midi_message(1000, 60));
messages.add(midi_message(1000, 60));
messages.add(midi_message(1001, 60));
messages.add(midi_message(1002, 70));
messages.add(midi_message(1002, 60));
messages.remove_first_note_like(60);
messages.remove_all_before(1001);
}
Solution with Boost.MultiIndex:
Live Coliru Demo
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
using namespace boost::multi_index;
struct IMidiMsgExt
{
int mTick;
int mTone;
};
using MidiSet=multi_index_container<
IMidiMsgExt,
indexed_by<
ordered_unique<member<IMidiMsgExt,int,&IMidiMsgExt::mTick>>,
hashed_non_unique<member<IMidiMsgExt,int,&IMidiMsgExt::mTone>>
>
>;
#include <iostream>
int main()
{
MidiSet m={{0,100},{2,60},{3,150},{5,60},{1,200},{4,90}};
std::cout<<"before erasing:\n";
for(const auto& msg:m)std::cout<<"["<<msg.mTick<<","<<msg.mTone<<"]";
std::cout<<"\n";
m.get<1>().erase(60);
std::cout<<"after erasing:\n";
for(const auto& msg:m)std::cout<<"["<<msg.mTick<<","<<msg.mTone<<"]";
std::cout<<"\n";
}
Output
before erasing: [0,100][1,200][2,60][3,150][4,90][5,60] after erasing: [0,100][1,200][3,150][4,90]