使用自定义比较器返回一个std::set。

4

我正在尝试编写一个函数,返回一个具有自定义比较器的std::set(按照这个答案的建议)。代码如下:

#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链接,但在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?


1
我认为是库太过严格了。微软的库要求lambda有一个赋值运算符,但是a)由于您在lambda类型的const版本上实例化了std::set,所以这不会发生;b)对于闭包类型,在C++20之前隐式删除了它;c)这不应该是必需的,因为(尽管cppreference只需要复制构造函数),但(毫无疑问地)查看cppreference并没有要求它是可复制或可移动的。 - HTNW
可能是我的天真,但当使用“std :: set mySet {{13, 31},cmp};”时,在MSVC 2019下成功似乎很有趣。 - Aluan Haddad
可能代码行 auto mySet = GetSet(); 首先想要推断出 mySet 的类型,但是由于它不知道关于 lambda 比较器的任何信息,所以无法推断。 - dgrandm
2
@dgrandm 比较器的类型是从 auto GetSet() {...} 推导出的返回类型推导出的。 - Aluan Haddad
你链接的答案说这是针对C++20而不是C++17的。 - phuclv
显示剩余2条评论
1个回答

0

我不知道出了什么问题(是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;
}

能够在两种编译器上正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接