【发布时间】: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() {...}推导出的返回类型推导出来的