模板化一个类,然后重载运算符 (C++)

Posted

技术标签:

【中文标题】模板化一个类,然后重载运算符 (C++)【英文标题】:Templating a class and then overloading operators (C++) 【发布时间】:2014-11-17 11:22:09 【问题描述】:

下面的代码不起作用,我找不到原因,非常感谢任何帮助。

//In Maths.h file

template <class T> class Maths
public:
    Maths<T>(T lhs);

    template<typename U>
    Maths<T>(const Maths<U>& otherMaths);

    ~Maths();

    template <typename U>
    Maths<T>& operator+(const Maths<U>& rhs);

    template <typename U> 
    Maths<T>& operator*(const Maths<U>& rhs);

    template <typename U> 
    Maths<T>& operator-(const Maths<U>& rhs);

private:
    T _lhs;
;



//In Maths.cpp file
#include "Maths.h"

template <class T>
Maths<T>::Maths(T lhs)
    _lhs = lhs;
    return _lhs;


template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
    _lhs = otherMaths._lhs;


template <class T>
Maths<T>::~Maths()

template <class T> template <typename U>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return Maths._lhs + rhs; 

template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<T>& rhs) return Maths._lhs - rhs; 

template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<T>& rhs) return Maths._lhs * rhs; 

问题在于 VS 无法识别关键字运算符(即不显示为蓝色),这是为什么呢?

编辑:

我已经删除了下面指出的错误。将所有定义移到 .h 文件中,代码仍然无法编译,此处发现错误:http://i.imgur.com/Z9rWOFh.png

新代码(如果有兴趣):

//in Maths.h file
template <class T> class Maths
public:
    Maths<T>(T lhs);

    template<typename U>
    Maths<T>(const Maths<U>& otherMaths);

    ~Maths();

    T& getValue() return _lhs; ;

    template <typename U>
    Maths<T>& operator+(const Maths<U>& rhs);

    template <typename U> 
    Maths<T>& operator*(const Maths<U>& rhs);

    template <typename U> 
    Maths<T>& operator-(const Maths<U>& rhs);

private:
    T _lhs;
;

template <class T>
Maths<T>::Maths(T lhs)
    _lhs = lhs;


template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
    _lhs = otherMaths.getValue();


template <class T>
Maths<T>::~Maths()

template <class T>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return _lhs + rhs.getValue(); 

template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<U>& rhs) return _lhs - rhs.getValue(); 

template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<U>& rhs) return _lhs * rhs.getValue(); 

//in main.cpp

#include "Maths.h"

int main()
    Maths<int> x = 1;
    Maths<int> y = 5;
    x + y;
    return 0;

【问题讨论】:

您不需要在Maths 之后为您的内联成员函数返回类型指定&lt;T&gt;,也不需要为构造函数名称指定。 请阅读Why can templates only be implemented in the header file? 然后,我建议使用 g++ 或 clang++ 以获得可以理解的错误消息:coliru.stacked-crooked.com/a/9aaa7134ef8a6c28 我建议你阅读this - 你有很多基本错误。 @TonyD 我更担心 VS 不将运算符识别为关键字的原因。这段代码(连同我拥有的 main.cpp)在 g++ 中运行良好,但我在大学课程的要求是代码要在 VS 上运行。您能看到我的代码无法将运算符识别为关键字的任何原因吗? (例如:在上面的代码 sn-p 上它读起来很好,而在 VS 上它看起来像这样i.imgur.com/upahPNx.png) 如果某些东西适用于 g++ 并不意味着它应该适用于另一个编译器。有些行为在标准上是未定义的,有些编译器实现了“预期的”行为,而另一些则没有。我强烈建议您修复 cmets 和 answers 指出的错误,然后看看它是否仍然不起作用。 【参考方案1】:
    不能在多个文件中分离模板类的声明和实现。因此,您需要将所有实现移动到标题中。 您有很多现在看不到的错误(例如在构造函数中返回)。我建议您在类声明中移动实现。更正它、调试、做一些测试,然后如果您仍然需要它,请尝试将实现移到外面。 Visual Studio(或本例中的 IntelliSense)有时会在突出显示时出现一些错误(或者可能只是速度很慢)。不要专注于此。如果出现问题,编译器会为您提供更准确的错误和警告。

我可以告诉你一些错误:

    return 在构造函数中 Maths&lt;T&gt;( T lhs ); return Maths._lhs + rhs; - Maths 是一个类,但您使用实例进行操作。如果您需要获取指向当前实例的指针,请使用this-&gt;_lhs,或者只使用_lhs_lhs = otherMaths._lhs; - 您无法访问 private 字段;您可以获得Maths&lt; T &gt; 类的值_lhs,但Maths&lt; U &gt; 是一个不同的类。所以你需要做一些像T&amp; value( ) return _lhs; 这样的函数并在这里使用它;

编辑:

还有一些错误。正如您在错误描述中看到的,您的实现

template <class T>
Maths<T> Maths<T>::operator+(const Maths<T>& rhs) return _lhs + rhs.getValue(); 

与函数定义不匹配

// in class template <class T> class Maths
template <typename U>
Maths<T>& operator+(const Maths<U>& rhs);

(就像一个游戏 - 找出不同之处 =D) 正确的做法是这样的:

// declaration
template <typename U>
Maths<T> operator+(const Maths<U>& rhs);
// ...
// definition
template <class T>
template <typename U>
Maths<T> Maths<T>::operator+(const Maths<U>& rhs)  return _lhs + rhs.getValue( ); 

我已从声明中删除 &amp; 并将 template &lt;typename U&gt; 添加到定义中。对于operator-operator*,您需要删除&amp;。 下一个问题你会发现getValue 没有常量声明。您需要添加新方法。

const T& getValue( ) const  return _lhs; 

【讨论】:

关于 1.:不,您可以将它们分开。对于泛型编程的非常特殊的情况,比如当你只支持浮动类型时,这甚至是有意义的。这里的关键词是“显式专业化”。 @phresnel 是对的。另一种方法是在类声明之后将.cpp 包含在.h 文件中。我认为这里的问题不是分离。 @NikolayKondratyev:我希望你在.h 中测量.inl 我已经更新了主要问题正文中的代码和我的编译器错误 @NikolayKondratyev 抱歉,由于草率,我错过了您在我的编辑答案中提出的大部分观点(我的讲师正在测试某些东西,但在编译失败后我忘记将其改回)删除和引用允许我的代码编译,我只是在写草率和糟糕的代码。我决心在这方面做得更好!非常感谢大家的帮助!【参考方案2】:

哎呀...您还没有采纳早期反馈。下面是一些可编译的代码:

template <class T>
class Maths

  public:
    Maths(T lhs);

    template<typename U>
    Maths(const Maths<U>& otherMaths);

    ~Maths();

    T& getValue()  return _lhs; ;
    const T getValue() const  return _lhs; ;

    template <typename U>
    Maths<T> operator+(const Maths<U>& rhs);

    template <typename U> 
    Maths<T> operator*(const Maths<U>& rhs);

    template <typename U> 
    Maths<T> operator-(const Maths<U>& rhs);

  private:
    T _lhs;
;

template <class T>
Maths<T>::Maths(T lhs)
    _lhs = lhs;


template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
    _lhs = otherMaths.getValue();


template <class T>
Maths<T>::~Maths()

template <class T> template <typename U>
Maths<T> Maths<T>::operator+(const Maths<U>& rhs) return _lhs + rhs.getValue(); 

template <class T> template <typename U>
Maths<T> Maths<T>::operator-(const Maths<U>& rhs) return _lhs - rhs.getValue(); 

template <class T> template <typename U>
Maths<T> Maths<T>::operator*(const Maths<U>& rhs) return _lhs * rhs.getValue(); 

//in main.cpp

#include "Maths.h"

int main()

    Maths<int> x = 1;
    Maths<int> y = 5;
    x + y;

请注意,编译所需的更正包括将const 函数添加到getValue,将运算符声明更改为按值而不是按引用返回Math&lt;T&gt;s。

话虽如此,将Math&lt;int&gt; 添加到Math&lt;double&gt; 返回Math&lt;int&gt; 并没有多大意义,因为这在这两种类型中不太精确。下面的代码使用decltype 来选择 C++ 本身在对这两种类型进行操作时使用的相同类型,例如int 乘以 double 返回 double,将 uint8_t(又名 unsigned char)添加到 unsigned int 返回另一个 unsigned int。我还放弃了n__lhs 成员变量名称,因为_lhs 仅适用于运营商内部的一个相当短视的角度...... rhs 的“_lhs”正在使用但没有无论如何都有意义...

template <class T>
class Maths

  public:
    Maths(T n);

    template<typename U>
    Maths(const Maths<U>& otherMaths);

    ~Maths();

    T& getValue()  return n_; ;
    const T getValue() const  return n_; ;

    template <typename U>
    Maths<decltype(T()+U())> operator+(const Maths<U>& rhs);

    template <typename U> 
    Maths<decltype(T()*U())> operator*(const Maths<U>& rhs);

    template <typename U> 
    Maths<decltype(T()-U())> operator-(const Maths<U>& rhs);

private:
    T n_;
;

template <class T>
Maths<T>::Maths(T n)
    n_ = n;


template <class T> template <typename U>
Maths<T>::Maths(const Maths<U>& otherMaths)
    n_ = otherMaths.n_;


template <class T>
Maths<T>::~Maths()

template <class T> template <typename U>
Maths<decltype(T()+U())> Maths<T>::operator+(const Maths<U>& rhs)
 return getValue() + rhs.getValue(); 

template <class T> template <typename U>
Maths<decltype(T()-U())> Maths<T>::operator-(const Maths<U>& rhs)
 return getValue() - rhs.getValue(); 

template <class T> template <typename U>
Maths<decltype(T()*U())> Maths<T>::operator*(const Maths<U>& rhs)
 return getValue() * rhs.getValue(); 

//in main.cpp

#include "Maths.h"

int main()

    Maths<int> x = 1;
    Maths<int> y = 5;
    x + y;
 

【讨论】:

以上是关于模板化一个类,然后重载运算符 (C++)的主要内容,如果未能解决你的问题,请参考以下文章

模板类运算符重载多个类型名 C++

如何为从C++中的模板继承的类重载赋值运算符

重载 [] 和 = 运算符以在 C++ 中接受我的模板类的值

类模板 友元重载形式 各种运算符重载 new delete ++ = +=

C++学习:5其他语法

c ++模板类中的运算符重载