Return a std::set with a custom comparator

Viewed 308

I'm trying to write a function to return a std::set with a custom comparator (per the advice from this answer), as follows:

#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 << " ";
}

Obviously this is for demonstration purposes, my class is more complex than an int

It works fine in GCC Coliru link, but does not work in VS2019. In VS2019 (using /std:c++17) it produces the following error:

Error C2783 'void std::swap(_Ty &,_Ty &) noexcept()': could not deduce template argument for '_Enabled' C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.27.29110\include\utility 114

If I change the code to not use the function, and instead have:

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 << " ";
}

It works correctly. Is there anything wrong with the above, or is Microsoft being more pedantic, or some kind of compiler bug?

1 Answers

I don't have an answer on what's going wrong (whether GCC is being sloppy or MSVC is being more pedantic), but you can use the following instead:

#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;
}

Which works on both compilers.

Related