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)
  • std::更大的
    (案例2)
  • lambda函数(情况3)
前两种选择是成功的。但是lambda作为一个自定义比较函数的情况下,它不起作用。以下是MCVC:

#包括
#包括
#包括
#包括
#包括
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);
这是因为lambda
compare
必须传递给
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;
}