C++11 为什么我们不能使用带有自定义比较lambda的'std::multiset'作为'std::map'的值?
这是一个后续问题 我试着用下面的方法来解决 基本的 可以为类成员的C++11 为什么我们不能使用带有自定义比较lambda的'std::multiset'作为'std::map'的值?,c++11,c++20,c++17,c++,lambda,multiset,custom-compare,C++11,C++20,C++17,C++,Lambda,Multiset,Custom Compare,这是一个后续问题 我试着用下面的方法来解决 基本的 可以为类成员的std::multiset提供自定义比较lambda函数(因为),如下所示: #include <iostream> #include <set> const auto compare = [](int lhs, int rhs) noexcept { return lhs > rhs; }; struct Test { std::multiset<int, decltype(com
std::multiset
提供自定义比较lambda函数(因为),如下所示:
#include <iostream>
#include <set>
const auto compare = [](int lhs, int rhs) noexcept { return lhs > rhs; };
struct Test
{
std::multiset<int, decltype(compare)> _set{compare};
Test() = default;
};
我尝试将std::multiset
与自定义
- 函子
比较
(案例1)
(案例2)std::更大的
- lambda函数(情况3)
#包括
#包括
#包括
#包括
#包括
const auto compare=[](int-lhs,int-rhs)noexcept{return-lhs>rhs;};
课堂测试
{
私人:
结构比较
{
bool运算符()(const int lhs,const int rhs)const noexcept{return lhs>rhs;}
};
私人:
//std::multiset dummy;//工作正常
//std::multiset dummy;//工作正常
std::multiset dummy{compare};//不起作用
使用CustomMultiList=decltype(虚拟);
公众:
std::映射脚本{};
};
int main()
{
测试t{};
t、 脚本[“Linux”]。插入(5);
t、 脚本[“Linux”]。插入(8);
t、 脚本[“Linux”]。插入(0);
对于(自动a:t.scripts[“Linux”]){
std::cout要在一行中完成,您需要以下内容:
t.scripts.try_emplace("Linux", compare).first->second.insert(5);
这是因为lambdacompare
必须传递给multiset
的构造函数。否则就没有比较对象,无法构造multiset
演示:
听起来好像我试图默认构造传递的lambda,它
直到。如果是这种情况,发生在哪里
是的。这正是这里发生的事情,也是由于电话线的呼叫
让我们看一下细节。上面的调用将导致以下重载的调用,因为键是临时的std::string
,由const char*
构造而成
T& operator[]( Key&& key );
自:
闭包类型是不可默认构造的
已删除(C++14之前)没有(C++14之后)默认构造函数。(C++20之前)
如果未指定捕获,则闭包类型具有默认值
构造函数。否则,它没有默认构造函数(包括
存在捕获默认值的情况,即使它实际上不存在
捕获任何东西。(从C++20开始)
这意味着,lambda闭包类型的默认构造在C++17中不可用(这就是编译器错误所抱怨的)
另一方面,在compare
lambda中没有指定捕获(即无状态lambda),因此支持C++20标准的编译器可以显式默认该捕获
是否可以使用lambda比较函数解决此问题
收银范围
不是通过使用std::map::operator[]
(正如上面解释的原因),而是是的,正如@JohnZwinck在他的回答中提到的那样。我想解释一下,这是如何工作的
的构造函数之一提供了传递比较器对象的可能性
template< class InputIt >
multiset( InputIt first, InputIt last,
const Compare& comp = Compare(),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const Allocator& alloc = Allocator() );
@JeJo:不,需要比较器来构造multiset
。如果您不喜欢,只需创建一个包装类my_multiset
,其默认构造函数使用compare
构造multiset
。
t.scripts.try_emplace("Linux", compare).first->second.insert(5);
t.scripts["Linux"].insert(5);
// ^^^^^^^^^
T& operator[]( Key&& key );
return this->try_emplace(
std::move(key)).first -> second;
// key_type mapped_type
// ^^^^^^^^ ^^^^^^^^^^^
// | |
// | |
// (std::string) (std::multiset<int, decltype(compare)>)
// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// | | (default-construction meaning)
// | default-construction --> std::multiset<int, decltype(compare)>{}
// move-construction ^^
ClosureType() = delete; (until C++14)
ClosureType() = default; (since C++20)(only if no captures are specified)
template< class InputIt >
multiset( InputIt first, InputIt last,
const Compare& comp = Compare(),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
const Allocator& alloc = Allocator() );
std::multiset<int, decltype(compare)> dummy{ compare }; // copying
std::multiset<int, decltype(compare)> dummy{ std::move(compare) }; // moving
template <class... Args>
pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
#include <iostream>
#include <string>
#include <map>
#include <set>
// provide a lambda compare
const auto compare = [](int lhs, int rhs) noexcept { return lhs > rhs; };
class Test
{
private:
// make a std::multi set with custom compare function
std::multiset<int, decltype(compare)> dummy{ compare };
using CustomMultiList = decltype(dummy); // use the type for values of the map
public:
std::map<std::string, CustomMultiList> scripts{};
// warper method to insert the `std::multilist` entries to the corresponding keys
void emplace(const std::string& key, const int listEntry)
{
scripts.try_emplace(key, compare).first->second.emplace(listEntry);
}
// getter function for custom `std::multilist`
const CustomMultiList& getValueOf(const std::string& key) const noexcept
{
static CustomMultiList defaultEmptyList{ compare };
const auto iter = scripts.find(key);
return iter != scripts.cend() ? iter->second : defaultEmptyList;
}
};
int main()
{
Test t{};
// 1: insert using using wrapper emplace method
t.emplace(std::string{ "Linux" }, 5);
t.emplace(std::string{ "Linux" }, 8);
t.emplace(std::string{ "Linux" }, 0);
for (const auto a : t.getValueOf(std::string{ "Linux" }))
{
std::cout << a << '\n';
}
// 2: insert the `CustomMultiList` directly using `std::map::emplace`
std::multiset<int, decltype(compare)> valueSet{ compare };
valueSet.insert(1);
valueSet.insert(8);
valueSet.insert(5);
t.scripts.emplace(std::string{ "key2" }, valueSet);
// 3: since C++20 : use with std::map::operator[]
// latest version of GCC has already included this change
//t.scripts["Linux"].insert(5);
//t.scripts["Linux"].insert(8);
//t.scripts["Linux"].insert(0);
return 0;
}