标准算法比较器接受不同类型的对象是否合法?

Is it legal for a standard algorithm comparator to accept objects of different types?

本文关键字:是否 对象 同类型 比较器 算法 标准      更新时间:2023-10-16

最近在Stack Overflow上发布的一个答案显示了为标准算法提供一个接受不同类型操作数的比较器的代码:

2。对模板化的operator()使用比较器

不使用lambda,而是用模板化的operator()定义一个函子。

struct comparator
{
    template<typename T, typename U>
    bool operator()(T const& lhs, U const& rhs) const {
        return lhs.mCommonField < rhs.mCommonField;
    }
};

那么,就像这样简单:

std::sort(aStructs.begin(), aStructs.end(), comparator{});
std::sort(bStructs.begin(), bStructs.end(), comparator{});
// ...
std::set_intersection(aStructs.begin(), aStructs.end(),
                      bStructs.begin(), bStructs.end(),
                      std::back_inserter(intersection),
                      comparator{}
                      );

请注意,由于比较器中有一个模板,它必须在函数作用域之外声明。Coliru Viewer.

显然,这至少在实践中是可行的,正如工作的实时演示所证明的那样。

但是标准严格允许吗?

标准中相应的章节是§25.4。关于Compare参数类型的唯一要求在§25.4/2中:

Compare是函数对象类型。应用于类型为Compare的对象的函数调用操作的返回值,在上下文中转换为bool时,如果调用的第一个参数小于第二个参数,则返回true,否则返回falseCompare comp一直用于假设排序关系的算法。假定comp不会通过解引用迭代器应用任何非常数函数。

换句话说,当调用

时,它不能改变迭代器所指向的值,并且应该对值产生严格的弱排序。由于比较器满足这两个要求,是的,它是合法的!

实际上,这种比较函子正是N3421 -制作操作符函子greater<>中提出的,现在是c++ 14标准的一部分。它为标准库函数提供void专门化,以完善与相应操作符(如果有的话)的前向比较。例如(取自提案文件):

namespace std
{
    template <> struct greater<void> {
      template <class T, class U> auto operator()(T&& t, U&& u) const
        -> decltype(std::forward<T>(t) > std::forward<U>(u))
           { return std::forward<T>(t) > std::forward<U>(u); }
    };
}