我需要更改多集的“键”:
multiset<IMidiMsgExt, IMidiMsgExtCompByNoteNumber> playingNotes;
例如当我使用
.find()
函数时,它将搜索并返回具有该NoteNumber
属性值的第一个对象(迭代器)。我说“第一个”是因为我的多集列表可能包含带有相同“键”的对象。所以我做了:
struct IMidiMsgExtCompByNoteNumber {
bool operator()(const IMidiMsgExt& lhs, const IMidiMsgExt& rhs) {
return lhs.NoteNumber() < rhs.NoteNumber();
}
};
但是当我尝试这样做时:
auto it = playingNotes.find(60);
编译器说
no instance of overloaded function "std::multiset<_Kty, _Pr, _Alloc>::find [with _Kty=IMidiMsgExt, _Pr=IMidiMsgExtCompByNoteNumber, _Alloc=std::allocator<IMidiMsgExt>]" matches the argument list
我会误会整个事情吗?怎么了?
最佳答案
我相信您在这里有一些误解:
associative container类型的一部分是键类型和比较器。因为C ++是强类型的,所以更改容器上比较器的唯一方法是创建一个新容器,将所有元素复制或移动到其中
在容器中创建所有元素的副本是一个潜在的昂贵过程
通过创建副本,您违反了Single Source of Truth最佳做法multiset
很少使用,我在职业生涯中使用过一次,其他人指出了它的缺点,建议您使用use another container,write your own container,或者在我的情况下,我建议仅使用vector
并对其进行排序何时需要的方式
我将对您的评论进行分类,以显示the answer I've already given you的正确性:
我们将假设您选择的multiset<IMidiMsgExt, IMidiMsgExtCompByNoteNumber>
是必需的,并且无法通过使用vector
进行改进,如4中所建议,其中:
struct IMidiMsgExtCompByNoteNumber {
bool operator()(const IMidiMsgExt& lhs, const IMidiMsgExt& rhs) {
return lhs.NoteNumber() < rhs.NoteNumber();
}
};
您不能使用
multiset::find
,因为这要求您指定要搜索的确切IMidiMsgExt
。因此您需要使用find_if(cbegin(playingNotes), cend(playingNotes), [value = int{60}](const auto& i){return i.mNote == value;})
搜索特定的属性值。可以直接在PlayingNotes
上使用而无需更改排序,因为you say:我想删除具有60个mNote的第一个音符。无论删除时的mTime。
您需要捕获[
find_if
]的结果,检查它是否有效,如果erase
如my answer中所示,对它进行验证,因为you say:找到的第一个元素将为此找到并擦除。 [原文]
我会将代码从答案中滚动到一个函数中,因为you say:
我想起来是否想删除另一个元素(可能具有相同的值)被删除[病]
最终的解决方案应该是编写一个如下所示的函数:
bool foo(const multiset<IMidiMsgExt, IMidiMsgExtCompByNoteNumber>& playingNotes, const int value) {
const auto it = find_if(cbegin(playingNotes), cend(playingNotes), [=](const auto& i){return i.mNote == value;});
const auto result = it != cend(playingNotes);
if(result) {
playingNotes.erase(it);
}
return result;
}
您可以这样称呼它:
foo(playingNotes, 60)
如果您想知道某个元素是否已删除,则可以测试foo
的返回值。