为模板类重载运算符时的隐式转换

时间:2023-03-10
本文介绍了为模板类重载运算符时的隐式转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我想知道为什么隐式类型转换不适用于类模板上的外部运算符重载.这是工作的非模板版本:

I would like to know why implicit type conversion doesn't work with outside operator overloading on class templates. Here is the working, non-templated version:

class foo
{
public:

    foo() = default;

    foo(int that)
    {}

    foo& operator +=(foo rhs)
    {
        return *this;
    }
};

foo operator +(foo lhs, foo rhs)
{
    lhs += rhs;
    return lhs;
}

正如预期的那样,以下几行编译正确:

As expected, the following lines compile correctly:

foo f, g;
f = f + g; // OK
f += 5; // OK
f = f + 5; // OK
f = 5 + f; // OK

另一方面,当类 foo 被声明为一个简单的模板时:

On the other hand, when class foo is declared as a simple template like this:

template< typename T >
class foo
{
public:

    foo() = default;

    foo(int that)
    {}

    foo& operator +=(foo rhs)
    {
        return *this;
    }
};

template< typename T >
foo< T > operator +(foo< T > lhs, foo< T > rhs)
{
    lhs += rhs;
    return lhs;
}

以下几行编译出错:

foo< int > f, g;
f = f + g; // OK
f += 5; // OK
f = f + 5; // Error (no match for operator+)
f = 5 + f; // Error (no match for operator+)

我想了解为什么编译器 (GCC 4.6.2) 无法使用类模板版本的转换构造函数执行隐式类型转换.这是预期的行为吗?除了手动创建所有必要的重载之外,是否有任何解决方法?

I would like to understand why the compiler (GCC 4.6.2) is unable to perform implicit type conversion using the converting constructor for the template version of the class. Is that the expected behaviour? Apart from manually creating all the necessary overloads, is there any workaround for this?

推荐答案

它不正常工作的原因是隐式类型转换(即通过构造函数)在模板参数推导期间不适用.但是如果你让外部操作符成为朋友,那么它就可以工作,因为类型 T 是已知的,允许编译器调查可以转换什么来使参数匹配.

The reason it does not just work is that implicit type conversions (that is, via constructors) do not apply during template argument deduction. But it works if you make the outside operator a friend since then the type T is know, allowing the compiler to investigate what can be casted to make the arguments match.

我根据您的示例(但删除了 C++11 内容)制作了一个示例,其灵感来自 Scott Meyers Effective C++(第 3 版)中的第 46 项(有理数类).您的问题几乎与该项目完全匹配.Scott 还指出……这种朋友的使用与类的非公共部分的访问无关."

I made an example based on yours (but removed C++11 stuff), inspired by Item 46 (a rational number class) in Scott Meyers Effective C++ (ed 3). Your question is almost an exact match to that item. Scott also notes that ... "this use of friend is not related to the access of non-public parts of the class."

这也将允许混合使用 foo<T>, foo 等等,只要可以添加 T 和 U 等等

This will also allow work with mixes of foo< T >, foo< U > etc as long as T and U can be added etc.

另看这篇文章:C++加法重载歧义

#include <iostream>

using namespace std;

template< class T >
class foo
{
private:
   T _value;
public:
   foo() : _value() {}

   template <class U>
   foo(const foo<U>& that) : _value(that.getval()) {}

   // I'm sure this it can be done without this being public also;
   T getval() const { return _value ; }; 

   foo(const T& that) : _value(that) {}

   friend const foo operator +(foo &lhs,const foo &rhs) 
      {
     foo result(lhs._value+rhs._value); 
     return result;
      };
   friend const foo operator +(foo &lhs,const T &rhsval) 
      {
     foo result(lhs._value+rhsval); 
     return result;
      };
   friend const foo operator +(const T &lhsval,foo &rhs) 
      {
     foo result(lhsval+rhs._value); 
     return result;
      };

   friend foo& operator +=(foo &lhs,const foo &rhs)
      {
     lhs._value+=rhs._value;
     return lhs;
      };   
   friend std::ostream& operator<<(std::ostream& out, const foo& me){
      return out <<me._value;
   }
};

int main(){
   foo< int > f, g;
   foo< double > dd;
   cout <<f<<endl;
   f = f + g;
   cout <<f<<endl;
   f += 3 ;
   cout <<f<<endl;
   f = f + 5;
   cout <<f<<endl;
   f = 7 + f; 
   cout <<f<<endl;      
   dd=dd+f;
   cout <<dd<<endl;      
   dd=f+dd;
   cout <<dd<<endl;      
   dd=dd+7.3;
   cout <<dd<<endl;             
}

这篇关于为模板类重载运算符时的隐式转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!