【问题标题】:Templating a class and then overloading operators (C++)模板化一个类,然后重载运算符 (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 指出的错误,然后看看它是否仍然不起作用。

标签: c++ class templates syntax overloading


【解决方案1】:
  1. 不能在多个文件中分离模板类的声明和实现。因此,您需要将所有实现移动到标题中。
  2. 您有很多现在看不到的错误(例如在构造函数中返回)。我建议您在类声明中移动实现。更正它、调试、做一些测试,然后如果您仍然需要它,请尝试将实现移到外面。
  3. Visual Studio(或本例中的 IntelliSense)有时会在突出显示时出现一些错误(或者可能只是速度很慢)。不要专注于此。如果出现问题,编译器会为您提供更准确的错误和警告。

我可以告诉你一些错误:

  1. return 在构造函数中 Maths&lt;T&gt;( T lhs );
  2. return Maths._lhs + rhs; - Maths 是一个类,但您使用实例进行操作。如果您需要获取指向当前实例的指针,请使用this-&gt;_lhs,或者只使用_lhs
  3. _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;
} 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多