【问题标题】:template class instance receiving another instance of the same template class of different type模板类实例接收不同类型的相同模板类的另一个实例
【发布时间】:2013-09-12 04:10:35
【问题描述】:

模板类实例如何接收同一模板类的不同类型的另一个实例作为其某些函数成员的参数? (我很难用更简单的方式表达我的问题,对此我感到非常抱歉。)

这是一个工作代码。我创建了一个类并将其命名为 MyClass。它在其 operator= 和 operator+ 成员函数上接受相同类型(即 int)的相同模板类。

#include <iostream>
using namespace std;

template<class T>
class MyClass {
protected:
  T __val;
public:
  MyClass();
  MyClass(T val): __val(val) {}
  void operator= (const MyClass<T>& r)
  {
    __val = (T)r.__val;
  }
  const MyClass<T>& operator+ (const MyClass<T>& r)
  {
    return *(new MyClass<T>(__val + (T)r.__val));
  }
  T retval() {return __val;}
};

int main()
{
  MyClass<int> myclass1(1);
  MyClass<int> myclass2(2);
  MyClass<int> myclass3 = myclass1 + myclass2;
  cout << myclass3.retval() << endl;
  return 0;
}

出于以下目的,我对 operator= 和 operator+ 的参数的 __val 成员进行了类型转换:

int main()
{
  MyClass<int> myclass1(1);
  MyClass<double> myclass2(2.5);
  MyClass<int> myclass3 = myclass1 + myclass2;
  cout << myclass3.retval() << endl;
  return 0;
}

显然我会得到一个错误。我不能将 myclass2 作为参数传递给 myclass1 的 operator+,因为 MyClass&lt;int&gt;::operator+ 想要 MyClass&lt;int&gt; 参数,而不是 MyClass&lt;double&gt;。我知道我可以重载另一个接受MyClass&lt;double&gt; 的运算符+,但我也想使用其他数字类型,如浮点数、单数等。为所有这些数字类型创建重载函数会使我的代码更大,我显然不这样做'不想发生。

我必须对 MyClass 进行哪些更改才能使我的第二个主要功能正常工作?

【问题讨论】:

  • return *(new -- NONONONONONONDONTWHYNOSTOP。
  • 另外,__names 之类的保留用于实现,请勿使用。
  • Java++参考手册的另一章

标签: c++ templates


【解决方案1】:

您需要一个模板成员operator+。此外,它应该返回一个值,而不是引用:

template<class T>
class MyClass 
{
 public:
  template <typename T2>
  MyClass operator+ (const MyClass<T2>& r) const { return _val + r.retval(); }

  T retval() const {return _val;}

  // as before
};

请注意,这将在涉及operator+ 的表达式中返回与 LHS 相同类型的值。请注意,最好将operator+ 实现为非成员二元运算符。但是你必须实现一些编译时逻辑来确定返回类型:

template <typename T1, typename T2>
MyClass< ?? > operator+(const MyClass<T1>& lhs, const MyClass<T1>& rhs)
{
  return lhs.retval() + rhs.retval();
}

其中?? 应替换为编译构造以选择基于T1T2 的类型。据推测,这将是这两种类型中的一种。这是一个 C++11 示例:

template <typename T1, typename T2>
auto operator+(const MyClass<T1>& lhs, const MyClass<T1>& rhs)->decltype(lhs.retval()+rhs.retval())
{
  return lhs.retval() + rhs.retval();
}

这样做的好处是返回类型的确定与 LHS 或 RHS 上的内容无关。

【讨论】:

  • "It's throwing error" 并不是对所发生情况的非常有用的描述。阅读错误消息可能会指出问题所在。
  • 我建议使用类型特征来确定将 T 添加到 T1 的结果。
  • @juanchopanza 好的,+1
  • 感谢您的回答。我想我正在接近它,但我仍然遇到错误。编译器说error: passing 'const MyClass&lt;double&gt;' as 'this' argument of 'T MyClass&lt;T&gt;::retval() [with T = double]' discards qualifiers [-fpermissive] return (__val + r.retval());是什么意思?
【解决方案2】:

你可以这样写:

template<typename _Ty> MyClass<T> operator+ (const MyClass<_Ty>& r) {
   return MyClass<T>(__val + (static_cast<_Ty> (r.__val)) );
}

提供一个成员函数。但要更广泛地支持它,请执行以下操作:

template<typename _T,typename _Ty> MyClass<_T> operator+ (const Myclass<_T>& p,const MyClass<_Ty>& r) {
       return MyClass<T>(p.__val + (static_cast<_T> (r.__val)) );
    }

很遗憾,您必须将__val 设为公开

【讨论】:

    【解决方案3】:

    铸造比点具有更强的优先级,即代替

    (T)r.__val
    

    你必须写

    (T) (r.__val)
    

    更好,使用static_cast。 因此,定义operator +like

    template<class S>
    MyClass<T> operator+ (const MyClass<S>& r) {
       return MyClass<T>(__val + (static_cast<S> (r.__val)) );
    }
    

    或者根本不使用显式转换:

    template<class S>
    MyClass<T> operator+ (const MyClass<S>& r) {
       return MyClass<T>(__val + r.__val);
    }
    

    最好让retval返回一个const T &,在operator+的实现中使用retval(),让operator+成为non-member non-friend:

    template<class T>
    class MyClass {
    private:
      T m_val;
    public:
      MyClass(T val): m_val(val) {}
      const T & retval () const {return m_val;}
    };
    
    template<class T1, class T2>
    auto operator+ (const MyClass<T1>& r1, const MyClass<T2> & r2)
    -> MyClass < std::remove_const < std::remove_reference <
       decltype ( r1.retval () + r2.retval () ) 
    > > > {
        return r1.retval () + r2.retval ();
    }
    

    【讨论】:

    • __val 受到保护,因此如果 ST 是不同的类型,r.__val 将无法访问。
    • 最好让retval返回const T &amp;,在operator +的实现中使用retval (),并使operator +成为非会员非朋友。
    • 我同意。我使用了retval(),但让它按值返回。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多