c++ - 为什么类型推导对我的集合交集和集合差异调用不起作用?

标签 c++ c++11 stdset set-operations insert-iterator

我正在尝试编写一个小算法来查找两个集合的共同部分和独特部分,并且我想以通用的方式编写它,所以我有这个小例子:

#include "boost/tuple/tuple.hpp"
#include <set>

template <typename InputIt, typename Value = typename std::iterator_traits<InputIt>::value_type>
boost::tuple<std::set<Value>, std::set<Value>, std::set<Value>>
findUniqueAndCommon(InputIt fbegin, InputIt fend, InputIt sbegin, InputIt send)
{
    std::set<Value> setL(fbegin, fend);
    std::set<Value> setR(sbegin, send);

    std::set<Value> uniqueInCatalog1;
    std::set<Value> uniqueInCatalog2;
    std::set<Value> commonInBoth;

    std::set_difference(setL.begin(), setL.end(), setR.begin(), setR.end(), uniqueInCatalog1.begin());
    std::set_difference(setR.begin(), setR.end(), setL.begin(), setL.end(), uniqueInCatalog2.begin());
    std::set_intersection(setL.begin(), setL.end(), setR.begin(), setR.end(), commonInBoth.begin());
    return{ uniqueInCatalog1, uniqueInCatalog2, commonInBoth };
}

int main()
{
     std::set<int> x = {1, 2, 3};
     std::set<int> y = {4, 2, 3};
     findUniqueAndCommon<std::set<int>::iterator>(x.begin(), x.end(), y.begin(), y.end());

}

我的问题是为什么这个函数编译失败?我尝试了 gcc、clang 和 MSVC,但它们都失败了。可以在此处检查 Clang 的错误消息:
https://godbolt.org/g/gFZyzo

非常感谢。

最佳答案

原因是std::set的常用迭代器 - the one you get with begin() - 不适用于插入或删除,仅用于遍历集合中的内容。试试 std::inserter相反:

#include "boost/tuple/tuple.hpp"
#include <set>

template <typename InputIt, typename Value = typename std::iterator_traits<InputIt>::value_type>
boost::tuple<std::set<Value>, std::set<Value>, std::set<Value>>
findUniqueAndCommon(InputIt fbegin, InputIt fend, InputIt sbegin, InputIt send)
{
    std::set<Value> setL(fbegin, fend);
    std::set<Value> setR(sbegin, send);

    std::set<Value> uniqueInCatalog1;
    std::set<Value> uniqueInCatalog2;
    std::set<Value> commonInBoth;

    std::set_difference(setL.begin(), setL.end(), setR.begin(), setR.end(), std::inserter(uniqueInCatalog1, uniqueInCatalog1.end()));
    std::set_difference(setR.begin(), setR.end(), setL.begin(), setL.end(), std::inserter(uniqueInCatalog2, uniqueInCatalog2.end()));
    std::set_intersection(setL.begin(), setL.end(), setR.begin(), setR.end(), std::inserter(commonInBoth, commonInBoth.end()));
    return{ uniqueInCatalog1, uniqueInCatalog2, commonInBoth };
}

int main()
{
     std::set<int> x = {1, 2, 3};
     std::set<int> y = {4, 2, 3};
     findUniqueAndCommon<std::set<int>::iterator>(x.begin(), x.end(), y.begin(), y.end());
}

不过请注意:

  1. 您正在创建范围的集合拷贝;我不认为你真的需要那样做。只需使用范围 - set_differenceset_intersection 实际上适用于范围而不是集合。
  2. std::set 默认保持有序。您需要在运行此代码之前和之后订购它们吗?如果不是,请考虑选择不同的容器。另一方面,正如@n.m 指出的那样,set_differenceset_intersection 需要有序的容器。
  3. 您将对这两个集合进行三次迭代而不是一次(您可以使用自定义函数在有序容器上执行此操作)。
  4. C++ 标准有自己的元组 - std::tuple - 自 C++11 以来。

关于c++ - 为什么类型推导对我的集合交集和集合差异调用不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47621034/

相关文章:

c++ - 将 std::set 或 std::map 与共享内存一起使用

C++ 编译器选择了错误的命名空间

c++ - C++11 的编译器标志 - 找不到计时文件

c++ - 在 .cpp 文件中使用条件类型

c++ - 从构造函数参数推断 std::set 的 Compare 类型

c++ - 如何在 std::set<int> 中找到最大的 int?

c++ - 从资源加载图像失败

c++ - 在 3D 中查找垂直于两条相交线的点

c++ - ijg 的 JPEG 支持 - 获取访问冲突

c++ - std::vector 与一位读者和一位作者的多线程同步:仅在调整大小时锁定