首页 > 解决方案 > std::set 插入器不尊重自定义比较器。(可能的编译器错误?)

问题描述

我发现std::inserteron anstd::map<T, C>并不总是尊重自定义比较器,而是有时会退回到默认值operator</ std::less。有没有人知道为什么会这样?考虑到零星的性质,我觉得这可能是一个编译器错误。特别是,我有这样的功能:

template <typename T, typename C>
std::set<T, C> operator|(const std::set<T, C> &lhs, const std::set<T, C> &rhs)
{
  std::set<T, C> out;
  std::set_union(lhs.begin(), lhs.end(),
                 rhs.begin(), rhs.end(),
                 inserter(out, out.end()));
  return out;
}

但这并不总是使用我的自定义C比较器,有时(我知道,我也希望我能找到一个模式)会std::less改为使用。如果我用 maunal 构造替换它,则std::insert_iterator<std::set<T, C>>一切正常:

template <typename T, typename C>
std::set<T, C> operator|(const std::set<T, C> &lhs, const std::set<T, C> &rhs)
{
  std::set<T, C> out;
  std::set_union(lhs.begin(), lhs.end(),
                 rhs.begin(), rhs.end(),
                 std::insert_iterator<std::set<T, C>>(out, out.end()));
  return out;
}

我觉得这可能是一个编译器错误(gcc 版本 7.3.0),因为http://en.cppreference.com/w/cpp/iterator/inserter上提供的参考资料描述inserter为简单地委托给insert_iterator

template< class Container >
std::insert_iterator<Container> inserter( Container& c, typename Container::iterator i )
{
    return std::insert_iterator<Container>(c, i);
}

此外,官方 C++ 标准第 24.5.2.5 节(通过http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf访问,第 859 页)将插入器的定义作为返回与第一个参数中传递的相同类型的插入迭代器:

template <class Container>
      insert_iterator<Container> inserter(Container& x, typename Container::iterator i);

这显然不会在这里发生,因为返回insert_iterator的是 type 类std::set<T, C = std::less<T>>,而不是std::set<T, C>.

除了编译器错误之外,还有对此的解释吗?

标签: c++gcccompiler-errors

解决方案


“可能的编译器错误”之于 C++ 就像“它可能是狼疮”之于 House MD。

话虽如此,在Documentation之后,您似乎正在使用该函数的版本1),其中明确指出:

1) 使用 operator< 比较元素,并且范围必须相对于相同进行排序。

您应该做的是将您的比较器传递给std::set_union,根据该函数的版本3)

所以真正的谜团是:为什么有时会使用您的比较器。但是,由于您不尊重函数的先决条件:

范围必须相对于相同进行排序。

然后没有定义预期的行为,所以行为不是“不正确的”。


推荐阅读