std::set 插入器不尊重自定义比较器。 (可能的编译器错误?)
Posted
技术标签:
【中文标题】std::set 插入器不尊重自定义比较器。 (可能的编译器错误?)【英文标题】:std::set inserter not respecting custom comparator. (possible compiler bug?) 【发布时间】:2018-05-14 01:41:07 【问题描述】:我发现std::map<T, C>
上的std::inserter
并不总是尊重自定义比较器,而是有时会退回到默认的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
来代替。如果我用 std::insert_iterator<std::set<T, C>>
的 maunal 构造替换它,一切正常:
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
是针对 std::set<T, C = std::less<T>>
类型的类,而不是 std::set<T, C>
。
除了编译器错误,还有其他解释吗?
【问题讨论】:
与您的问题无关:啊,请不要覆盖此类 STL 类型的运算符。 假装它只是说operatorOr
,让我继续希望这是 Python... ;)
您正在编译哪个版本的标准(这在这里很重要)?
请发布 MCVE。如果您由于“零星”性质而遇到问题,那么至少可以更好地描述您的问题。例如。你是想说代码随机无法编译吗?如果重试,相同的代码是否会再次编译? “返回的 insert_iterator 用于 std::setset<T, C>
。它们是不同的类型。“可能的编译器错误”之于 C++ 就像“它可能是狼疮”之于 House MD。
话虽如此,在Documentation 之后,您似乎正在使用该函数的版本 1),其中明确指出:
1) 元素使用运算符
您应该做的是将您的比较器传递给std::set_union
,根据该函数的版本 3)。
所以真正的谜团是:为什么有时会使用您的比较器。但是,由于您不尊重函数的先决条件:
范围必须相对于相同的范围进行排序。
那么没有定义预期的行为,所以行为不是“不正确的”。
【讨论】:
啊,有道理。因此,从某种意义上说,编译器错误会在它确实起作用时出现,尤其是在我的第二个版本中,我手动构造了一个std::insert_iterator<std::set<T, C>>
,它确实起作用了,而且肯定不使用operator<
。
@Jackson,这不是真正的编译器错误,因为您违反了函数的先决条件(“范围必须相对于相同进行排序。”),所以你没有-mans 土地,任何可能产生的行为都是“正确的”。我已经修改了答案来解释它。以上是关于std::set 插入器不尊重自定义比较器。 (可能的编译器错误?)的主要内容,如果未能解决你的问题,请参考以下文章