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

标签 c++ templates operator-overloading implicit-conversion

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

class foo
{
public:

    foo() = default;

    foo(int that)
    {}

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

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

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

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

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

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) 无法使用类模板版本的转换构造函数执行隐式类型转换。这是预期的行为吗?除了手动创建所有必要的重载之外,还有什么解决方法吗?

最佳答案

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

我根据你的例子做了一个例子(但删除了 C++11 的东西),灵感来自 Scott Meyers Effective C++(ed 3)中的 Item 46(一个有理数类)。您的问题几乎与该项目完全匹配。 Scott 还指出……“这种对 friend 的使用与类的非公共(public)部分的访问无关。”

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

也可以看看这个帖子:C++ addition overload ambiguity

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

关于c++ - 为模板类重载运算符时的隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8890051/

相关文章:

c++ - 这个指针一旦创建会发生什么?

c++ - 无法调试到源代码

c++ - 如何在c++ unordered_map中设置值并返回引用?

c++ - 使用可变参数模板限制模板类的受支持类型

templates - node.js + express.js + dust.js 问题

c++ - 具有纯抽象基类的 CRTP : call overhead

c++ - 重载复合赋值运算符

c++ - 编译器不匹配模板类的嵌套类的非成员运算符<()

c++ - 如何获取 linux 的已知路径

f# - 如何使用重载的静态运算符