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

NoS*_*tAl 7 c++ c++11

最近发布在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;
    }
};
Run Code Online (Sandbox Code Playgroud)

然后,它就像:

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{}
                      );
Run Code Online (Sandbox Code Playgroud)

请注意,由于比较器中有模板,因此必须在函数范围之外声明.Coliru Viewer上的实例.

显然,这至少在实践中有效,正如工作现场演示所证明的那样.

但标准是否严格允许?

tcl*_*amb 11

标准中的相应部分是§25.4.对Compare参数类型的唯一要求见§25.4/ 2:

Compare是一个函数对象类型.应用于类型对象的函数调用操作的返回值Compare,在上下文转换为时bool,将产生true调用的第一个参数是否小于第二个,false否则.Compare 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); }
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 25.4第2段不是第25.4.2节(描述了`std :: nth_element`).在这附近我们经常写25.4/2或25.4p2. (3认同)