14

这个问题的灵感来自于 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::sorton std::vector<std::reference_wrapper<std::vector<int>>>

另一方面,只有当operator<定义为非模板 Koenig 算子时,所有问题都得到解决,例如

template <...>
class vector ... {
  friend bool operator<(const vector& a, const vector& b) {...}
};

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

4

1 回答 1

1

考虑这段代码(啊):

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: 错误:'operator<' 的重载不明确(操作数类型为 'A' 和 'A')a1 < a2;

原因当然是两个 operator< 都是完全匹配的。另一方面,如果我们将第一个 operator< 更改为(在类外部定义):

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<。我认为他们做出了正确的选择。

于 2015-05-15T20:30:40.050 回答