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 IMidiMsgExts 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]