模板运算符<没有叫

时间:2017-06-28 07:04:39

标签: c++ templates operator-overloading template-specialization

以下代码实现了模板类Data,其目的是比较其成员对象。目的是如果成员对象具有相同类型,则该对象的operator<用于比较,并且如果成员对象具有不同类型,则std::string&#39; s operator<用于成员对象的字符串化。

#include <iostream>
#include <sstream>

template <typename T>
class Data
{
public:
  Data( const T& t ) : m_data( t ) {}
  template <typename U> bool operator<( const Data<U>& cu )
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return ( static_cast<std::ostringstream&>(( std::ostringstream().flush() << m_data )).str() <
             static_cast<std::ostringstream&>(( std::ostringstream().flush() << cu.m_data )).str() );
  }

#if 1 // Change this to "#if 0" and code doesn't work anymore.
  bool operator<( const Data<T>& ct )
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return ( m_data < ct.m_data );
  }
#endif

private:
  T m_data;
  template< typename U> friend class Data;

friend bool operator< <T> ( const Data<T>&, const Data<T>& );
};

template<typename T>
bool operator<( const Data<T>& a, const Data<T>& b )
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  return ( a.m_data < b.m_data );
}

int main( int argc, char* argv[] )
{
  Data<int> a(10);
  Data<std::string> b("2");
  Data<int> c(2);
  std::cout << "10 < \"2\"? " << std::boolalpha << ( a < b ) << std::endl;
  std::cout << "10 < 2? " << std::boolalpha << ( a < c ) << std::endl;
  return 0;
}

我正在尝试使用成员operator<()而不是全局范围的operator<()。前者在#if 1块中演示,并按预期工作。当我尝试通过将#if 1更改为#if 0来强制使用后者时,代码不再符合要求:全局范围operator<()似乎不会被调用。

有人可以指出为什么全局范围的operator<()未被调用/不起作用,而成员operator<()会这样做吗?

1 个答案:

答案 0 :(得分:2)

这里发生的是@n.m. said in the comments。我花了一段时间来找出发生这种情况的确切原因,尽管最后它非常简单。

当您考虑运算符重载时,会生成一个可行函数列表,然后将其传递给算法,该算法将确定将调用哪些函数。特别是对于运算符重载,所考虑的函数列表是

16.3.1.2表达式中的运算符[over.match.oper / 6]

  

重载决议的候选函数集是成员候选人,非成员候选人和内置候选人的联合。

cppreference explains it in more detail

  

对于参数类型为T1的一元运算符@(删除cv资格后)或二元运算符@,其左操作数的类型为T1,右操作数的类型为T2(删除cv资格后),三组候选函数准备好了:

     

1)成员候选人:

     

2)非会员候选人:

     

3)内置候选人:

当发生重载解析时,成员函数会发生特殊情况(强调我的)

  

如果任何候选函数是成员函数(静态或非静态),而不是构造函数,它被视为具有额外参数(隐式对象参数)代表它们被称为的对象,并出现在第一个实际参数之前。

所以基本上你得到的重载是

template <typename U> 
bool operator<(EXACT_TYPE_PTR this, const Data<U>& cu );
template<typename T>
bool operator<(const Data<T>& a, const Data<T>& b)

EXACT_TYPE_PTR替换为您决定调用operator<的任何对象的类型。现在你有两个候选者,一个是模板,另一个是接受一个模板参数和一个模板参数。因此,首选具有确切类型的那个是优选的,因为它是完全匹配

注意你可能应该使成员operator<()函数为const,这样它就可以更通用并接受const参数。在当前情况下,如果你有一个const Data实例,那么将调用非成员重载