以下代码实现了模板类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<()
会这样做吗?
答案 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
实例,那么将调用非成员重载