为什么标准容器使用函数模板而不是非模板Koenig操作符

Why standard containers use function templates instead of non-template Koenig operators

本文关键字:是非 操作符 Koenig 函数模板 标准 为什么      更新时间:2023-10-16

这个问题的灵感来自Issue with std::reference_wrapper。比如说,用operator<代替std::vector。它被定义为函数模板

template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
                const vector<T,Alloc>& rhs );

因此,拒绝将函数实参隐式转换为相应函数形参的类型(主要是因为它的模板性质)。这大大降低了std::reference_wrapper的实用性和方便性。例如,不能在std::vector<std::reference_wrapper<std::vector<int>>>上使用std::sort

另一方面,只有将operator<定义为像 这样的非模板Koenig操作符,才能解决所有问题。
template <...>
class vector ... {
  friend bool operator<(const vector& a, const vector& b) {...}
};

我想知道为什么标准库采用了前一种方法而不是这种方法?

考虑以下代码:

template <class T>
class A {
  public:
  T m_x;
  friend bool operator<(const A & lhs, const A & rhs) {
    return lhs.m_x < rhs.m_x;
  }
};

和main.cpp:

#include "A.h"
namespace buddy {
bool operator<(const A<double> & lhs, const A<double> &rhs) {
    return lhs.m_x > rhs.m_x;
};
}
using namespace buddy;
int main(int argc, char ** argv) {
  A<double> a1;
  A<double> a2;
  a1 < a2;
  return 0;
}

这段代码不能编译:

main.cpp:14:5: error: ambiguous overload for ' operator<'(操作数类型为' A '和' A ')a1 & lt;a2;

原因当然是两个操作符<s都是精确匹配的。另一方面,如果我们改变第一个操作符><To(在类之外定义):>
template <class T>
bool operator<(const A<T> & lhs, const A<T> & rhs) {
  return lhs.m_x < rhs.m_x;
}

编译器不再抱怨:现在是精确匹配和函数模板之间的竞争,所以使用了精确匹配。

如果operator<如果按照你所建议的方式定义,std::vector的用户将没有合理的方法来重新定义operator><的行为,除非对std::vector本身进行专门化,这需要做更多的工作。>

总之,标准编写者选择使重载operator<比提供operator><这在某些情况下可能更有用。我认为他们的选择是正确的。>

相关文章: