为什么标准容器使用函数模板而不是非模板Koenig运算符 [英] Why standard containers use function templates instead of non-template Koenig operators

查看:195
本文介绍了为什么标准容器使用函数模板而不是非模板Koenig运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题的灵感来自 std :: reference_wrapper 问题。让我们举个例子, operator for std :: vector 。它定义为一个函数模板

  template<类T,类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 ;



另一方面,所有的问题只有在运算符< 被定义为非模板Koenig运算符,如

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

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

解决方案

考虑这个代码(Ah):

  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:

  #includeAh

namespace buddy {
bool operator<(const A< double>& lhs,const A double& rhs) {
return lhs.m_x> rhs.m_x;
};
}
使用命名空间buddy;
int main(int argc,char ** argv){

A< double> a1;
A< double> a2;

a1< a2;

return 0;
}

此代码不编译:



main.cpp:14:5:error:'operator<'(操作数类型是'A'和'A')的不明确重载
a1< a2;



当然的原因是两个运算符都是完全匹配的。另一方面,如果我们改变第一运算符(定义在类外):

 模板< class T& 
bool operator<(const A< T>& lhs,const A< T>& rhs){
return lhs.m_x& rhs.m_x;
}

编译器停止抱怨:现在是一个完全匹配和函数模板,因此使用完全匹配。



如果operator <是以你建议的方式定义的,std :: vector的用户没有合理的方法来重新定义operator< special of std :: vector自身的行为,这是一个更多的工作。 p>

总之,选择使标准作者更容易过载operator <在某些情况下可能更有用。我认为他们做出了正确的选择。


This question is inspired by Issue with std::reference_wrapper. Let' say, for example, operator< for std::vector. It's defined as a function template as

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

As a result, implicit conversion of function argument to the type of the corresponding function parameter is denied (basically because of its template nature). This greatly reduces the usefulness and convenience of std::reference_wrapper. For example, you cannot use std::sort on std::vector<std::reference_wrapper<std::vector<int>>>.

On the other hand, all the problems are solved only if operator< is defined as a non-template Koenig operator like

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

I'm wondering why the standard library has adopted the former approach instead of this?

解决方案

Consider this code (A.h):

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;
  }
};

And 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;
}

This code does not compile:

main.cpp:14:5: error: ambiguous overload for ‘operator<’ (operand types are ‘A’ and ‘A’) a1 < a2;

The reason of course is that both of the operator<'s are exact matches. On the other hand, if we change the first operator< to (defined outside the class):

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

The compiler stops complaining: it's now a competition between an exact match, and a function template, so the exact match is used.

If operator< was defined in the fashion that you're suggesting, there would be no reasonable way for users of std::vector to redefine the behavior of operator<, short of specializing std::vector themselves, which is a lot more work.

In conclusion, the standard writers elected to make it easier to overload operator<, than to provide an operator< that might be more useful in certain situations. I think they made the right choice.

这篇关于为什么标准容器使用函数模板而不是非模板Koenig运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆