【问题标题】:Return a std::set with a custom comparator返回带有自定义比较器的 std::set
【发布时间】:2020-09-14 04:13:25
【问题描述】:

我正在尝试编写一个函数来返回带有自定义比较器的std::set(根据this answer 的建议),如下所示:

#include <iostream>
#include <set>

auto GetSet()
{
    const auto cmp = [](auto n1, auto n2) { return n1 < n2; };
    std::set<int, decltype(cmp)> mySet(cmp); // compiler error, see below
    mySet.insert(13);
    mySet.insert(31);
    return mySet;
}
int main()
{
    auto mySet = GetSet();
    for (auto i : mySet)
        std::cout << i << " ";
}

显然这是出于演示目的,我的课程比int更复杂

它在 GCC Coliru link 中工作正常,但在 VS2019 中不起作用。在 VS2019 中(使用/std:c++17)会产生以下错误:

错误 C2783 'void std::swap(_Ty &,_Ty &) noexcept()': 无法推断 '_Enabled' C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC 的模板参数\Tools\MSVC\14.27.29110\include\utility 114

如果我将代码更改为不使用该功能,而是使用:

int main()
{
    const auto cmp = [](auto n1, auto n2) { return n1 < n2; };
    std::set<int, decltype(cmp)> mySet(cmp);
    mySet.insert(13);
    mySet.insert(31);
    for (auto i : mySet)
        std::cout << i << " ";
}

它工作正常。以上是不是有什么问题,还是微软比较迂腐,还是某种编译器的bug?

【问题讨论】:

  • 我认为是图书馆限制太多。 MS 的库希望 lambda 有一个赋值运算符,这 a) 没有发生,因为您在 lambda 类型的 const 版本中实例化了 std::set,b) 对于闭包类型隐式为 deleted,直到 C++ 20 和 c) 不应该是必要的,因为(诚然粗略)看一下 cppreference 表明它不需要复制或移动分配(它确实需要复制可构造性)。
  • @JaMiT 抱歉,我创建了一个测试 VS 项目,它似乎默认为 C++14。我将其更改为 C++17,但它仍然失败(这是意料之中的,因为我使用的项目是 C++17,我刚刚创建了一个测试应用程序以防万一),但我已经用来自 c++17 的错误消息更新了问题
  • 可能是我的幼稚,但有趣的是,在MSVC 2019下使用std::set mySet{ { 13, 31 }, cmp };推演指南时成功了
  • 可能auto mySet = GetSet(); 行想先推导出mySet 类型,但它不能,因为它对lambda 比较器一无所知。
  • @dgrandm 比较器的类型是从auto GetSet() {...}推​​导出的返回类型推导出来的

标签: c++ visual-studio-2019


【解决方案1】:

我不知道出了什么问题(GCC 是草率还是 MSVC 是更迂腐),但您可以改用以下方法:

#include <set>
#include <functional>
auto GetSet()
{
    const auto cmp = [](auto n1, auto n2) { return n1 < n2; };
    std::set<int, std::function<bool(int, int)>> mySet(cmp);
    mySet.insert(13);
    mySet.insert(31);
    return mySet;
}

这在两个编译器上都有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-07
    • 2022-01-28
    • 2021-10-23
    相关资源
    最近更新 更多