0

The code below isn't working and I can't find out the reason why, any help would be much appreciated.

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

The issue is in VS it is not recognizing the keyword operator (i.e. doesn't appear blue), why is this?

EDIT:

I have removed the errors pointed out below. Moved all definitions into .h file and the code still won't compile, errors found here: https://i.stack.imgur.com/fXGK5.png

new code (if interested):

//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;
}
  • You don't need to specify `` after `Maths` for your inline member function return types, nor for the constructor name. – Tony Delroy Nov 17 '14 at 11:36
  • Please read [Why can templates only be implemented in the header file?](http://stackoverflow.com/q/495021) Then, I recommend using g++ or clang++ for understandable error messages: http://coliru.stacked-crooked.com/a/9aaa7134ef8a6c28 – dyp Nov 17 '14 at 11:38
  • I suggest you have a read of [this](http://stackoverflow.com/questions/4421706/operator-overloading) - you've lots of basic errors. – Tony Delroy Nov 17 '14 at 11:45
  • @TonyD I'm more worried at the reason why VS doesn't recognize operator as a keyword. This code (along with the main.cpp I have) runs fine in g++ but the requirements for my course at university is that the code is to run on VS. Can you see any reason for my code to not recognize operator as a keyword? (example: on the code snippet above it reads fine where as on VS it looks like this http://i.imgur.com/upahPNx.png ) – Tommy Yardley Nov 17 '14 at 11:53
  • If something works on g++ doesn't mean it should work on another compiler. Some behaviours are undefined on the standard, and some compilers implement the "expected" behaviour while others don't. I highly encourage you to fix the mistakes pointed out by comments and answers and then see if it still don't work. – Gaston Nov 17 '14 at 12:28
  • Is your issue that this code doesn't compile? (If so, please show the actual errors). Or, are you only worried about the syntax highlighting even though it compiles and runs? – Useless Nov 17 '14 at 12:49
  • @TommyYardley: "The issue is in VS it is not recognizing the keyword operator (i.e. doesn't appear blue)" - when you have invalid code, it can confuse "intellisense" which is the Visual Studio syntax highlighting and symbol indexing system that decides whether to make your keywords blue or not. "I'm more worried at the reason why VS doesn't recognize operator as a keyword" - it's better to worry about causes not symptoms... until your code is valid and compiles cleanly, the colours may be wrong. – Tony Delroy Nov 17 '14 at 13:58
  • @TonyD okay thank you, makes a lot more sense now, thanks for your help – Tommy Yardley Nov 17 '14 at 15:05
  • i've uploaded my corrected code and the complier errors I receive when I run the code. Sorry about the delay in replying. – Tommy Yardley Nov 17 '14 at 15:23

2 Answers2

1
  1. You can't separate declaration and implementation of template class in multiple files. So you need to move all your implementations to the header.
  2. You have many error you don't see now (return in constructor for example). I recommend you to move implementations in class declaration. Correct it, debug, do some tests and then try to move implementations outside if you will still need it.
  3. Visual Studio (or IntelliSense in this case) sometimes can make some errors in highlighting (or it can be just slow). Don't focus on this. Compiler will give you more precise errors and warnings if there is something wrong.

Some errors I can tell you:

  1. return in constructor Maths<T>( T lhs );
  2. return Maths._lhs + rhs; - Maths is a class, but you make operations with an instance. If you need to take a pointer to current instance use this->_lhs, or just _lhs;
  3. _lhs = otherMaths._lhs; - you can't get an access to the private field; You can get a value _lhs of the class Maths< T >, but Maths< U > is a different class. So you will need to make some function like T& value( ) { return _lhs; } and use it here;

EDIT:

There are still some errors. As you can see in error description, your implementation

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

doesn't match function definition

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

(It's like a game - find the difference =D) The correct way is this:

// 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( ); }

I have removed the & from declaration and add template <typename U> to the defenition. For operator- and operator* you need to remove &. The next problen you will get that getValue does not have constant declaration. You need to add new method.

const T& getValue( ) const { return _lhs; }
Nikolay K
  • 3,770
  • 3
  • 25
  • 37
  • Regarding 1.: No, you _can_ separate them. For very special cases of generic programming, like for when you only support floating types, this can even make sense. Keyword here is "explicit specialisation". – Sebastian Mach Nov 17 '14 at 12:11
  • @phresnel is right. Another way is to include ``.cpp`` in ``.h`` file after class declaration. I think the question here is not in separation. – Nikolay K Nov 17 '14 at 12:26
  • @NikolayKondratyev: I hope you measn `.inl` in `.h`. – Jarod42 Nov 17 '14 at 14:13
  • I've updated my code in the main question body and my compiler errors – Tommy Yardley Nov 17 '14 at 15:22
  • @NikolayKondratyev sorry I missed most the points you made in your edited answer in mine due to sloppyness (my lecturer was testing something out and I forgot to change it back after it failed to compile still) removing the & references has allowed my code to compile, I was just writing sloppy and poor code. I'm determined to get better at this! Many thanks for everyones help! – Tommy Yardley Nov 17 '14 at 19:51
0

Yikes... you still haven't incorporate early feedback. Some compilable code below:

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

Note that the corrections needed to compile included adding a const function to getValue, changing the operator declarations to return Math<T>s by value rather than by reference.

All that said, it doesn't make a lot of sense to have say a Math<int> added to a Math<double> return a Math<int>, as that's the less precise of the two types. The code below uses decltype to pick the same type C++ itself uses when operating on the two types, so e.g. an int multiplied by a double returns a double, and a uint8_t (aka unsigned char) added to a unsigned int returns another unsigned int. I also ditch the _lhs member variable name for n_ as _lhs is only applicable from a rather myopic perspective inside the operators... the rhs's "_lhs" is being used which didn't make any sense anyway...

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;
} 
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252