0

I was working on templating my assignment here and when I tranfered code that should not have been in my previous cpp file to my header file, this cleared a lot of the issues I was having at I could not template inside the cpp file. Anyway after doing so I was left with two more errors that I am not sure how to fix as they are quite confusing.

LNK2019 unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class fractionType<float> const &)" (??6@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@AEBV?$fractionType@M@@@Z) referenced in function main

LNK2019 unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class fractionType<float> &)" (??5@YAAEAV?$basic_istream@DU?$char_traits@D@std@@@std@@AEAV01@AEAV?$fractionType@M@@@Z) referenced in function main   

LNK1120 2 unresolved externals

Here is my code

main.cpp

#include <iostream>
#include "fractiontype.h"

using namespace std;

int main() {

    //Fraction1 and Fraction2 Objects
    fractionType<float> fraction1(2, 3);
    fractionType<float> fraction2(0, 0);

    //Grab first fraction from user
    cout << "Enter a fraction in the form a/b: ";
    cin >> fraction1;

    //Grab second fraction from user
    cout << "Enter another fraction in the form a/b: ";
    cin >> fraction2;

    //Operators
    cout << fraction1 << " + " << fraction2 << " = " << fraction1 + fraction2 << "\n";
    cout << fraction1 << " - " << fraction2 << " = " << fraction1 - fraction2 << "\n";
    cout << fraction1 << " * " << fraction2 << " = " << fraction1 * fraction2 << "\n";
    cout << fraction1 << " / " << fraction2 << " = " << fraction1 / fraction2 << "\n";

    //Checking true or false statements
    cout << "\n" << fraction1 << " == " << fraction2;

    if (fraction1 == fraction2) {

        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " != " << fraction2;

    if (fraction1 != fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " < " << fraction2;

    if (fraction1 < fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " <= " << fraction2;

    if (fraction1 <= fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " > " << fraction2;

    if (fraction1 > fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    cout << fraction1 << " >= " << fraction2;

    if (fraction1 >= fraction2) {
        cout << " is true. \n";
    }
    else {
        cout << " is false. \n";
    }

    return 0;

}

fractiontype.h

#ifndef H_fraction
#define H_fraction

#include <iostream>

using namespace std;

template <class T>
class fractionType
{

    //overload the stream insertion and extraction operators

    friend ostream& operator<<(ostream&, const fractionType<T>&);

    friend istream& operator>>(istream&, fractionType<T>&);

public:

    //overload the assignment operator

    const fractionType<T>& operator=(const fractionType<T>&);


    //constructors

    fractionType();

    fractionType(const fractionType<T>&);

    fractionType(const float&, const float&);



    //desctructor

    ~fractionType();


    //oveload the relational operators

    bool operator==(const fractionType<T>&) const;

    bool operator!=(const fractionType<T>&) const;

    bool operator<=(const fractionType<T>&) const;

    bool operator<(const fractionType<T>&) const;

    bool operator>=(const fractionType<T>&) const;

    bool operator>(const fractionType<T>&) const;


    //overload the arithemetic operators

    fractionType<T> operator+(const fractionType<T>&);

    fractionType<T> operator-(const fractionType<T>&);

    fractionType<T> operator*(const fractionType<T>&);

    fractionType<T> operator/(const fractionType<T>&);





private:
    T numenator;      //variable to store the numerator
    T denominator;    //variable to store the denominator

};

template <class T>
fractionType<T>::fractionType(const float& nu, const float& de) {

    numenator = nu;

    if (de == 0) {
        cout << "\n\tInvalid demoninator. " << "Default value considered for denominator. ";

        denominator = 1;
    }
    else {

        denominator = de;
    }
}//end function fractionType


// Default constructor
template <class T>
fractionType<T>::fractionType() {

    numenator = 0;
    denominator = 1;
}

// copy constructor
template <class T>
fractionType<T>::fractionType(const fractionType<T>& rightFraction) {

    numenator = rightFraction.numenator;
    denominator = rightFraction.denominator;
}//end copy constructor


//Desctructor
template <class T>
fractionType<T>::~fractionType() {


}//end Desctructor

//oveload the relational operators
template <class T>
bool fractionType<T>::operator==(const fractionType<T>& rightFraction) const {

    return ((numenator == rightFraction.numenator) && (denominator == rightFraction.denominator));

}//end function operator==

template <class T>
bool fractionType<T>::operator!=(const fractionType<T>& rightFraction) const {

    return ((numenator != rightFraction.numenator) || (denominator != rightFraction.denominator));

}//end function operator!=

template <class T>
bool fractionType<T>::operator<(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) < (denominator * rightFraction.numenator));

}//end function operator<

template <class T>
bool fractionType<T>::operator<=(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) <= (denominator * rightFraction.numenator));

}//end function operator<=

template <class T>
bool fractionType<T>::operator>(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) > (denominator * rightFraction.numenator));

}//end function operator>

template <class T>
bool fractionType<T>::operator>=(const fractionType<T>& rightFraction) const {

    return ((numenator * rightFraction.denominator) >= (denominator * rightFraction.numenator));

}//end function operator>=




//overload the arithemetic operators
template <class T>
fractionType<T> fractionType<T>::operator+(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = (numenator * rightFraction.denominator) + (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator+

template <class T>
fractionType<T> fractionType<T>::operator-(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = (numenator * rightFraction.denominator) - (denominator * rightFraction.numenator);
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator-

template <class T>
fractionType<T> fractionType<T>::operator*(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    fractionHolder.numenator = numenator * rightFraction.numenator;
    fractionHolder.denominator = denominator * rightFraction.denominator;

    return fractionHolder;

}//end function operator*

template <class T>
fractionType<T> fractionType<T>::operator/(const fractionType<T>& rightFraction) {

    fractionType fractionHolder;

    //check for validity for division
    if (rightFraction.numenator == 0 || rightFraction.denominator == 0) {

        fractionHolder.numenator = 0;
        fractionHolder.denominator = 1;

        cout << "Invalid to perform division.";

    }
    else {

        fractionHolder.numenator = numenator * rightFraction.denominator;
        fractionHolder.denominator = denominator * rightFraction.numenator;

    }//end else - if x

    return fractionHolder;

}//end function operator+


//overload the stream extraction operators
template <class T>
ostream& operator<<(ostream& osObject, const fractionType<T>& myFraction) {

    osObject << myFraction.numenator << "/" << myFraction.denominator;

    return osObject;

}//end function operator<<

template <class T>
istream& operator>>(istream& isObject, fractionType<T>& myFraction) {

    char ch;

    isObject >> myFraction.numenator >> ch >> myFraction.denominator;

    return isObject;

}//end function operator>>

#endif

As I stated I moved a lot of my code from a previous cpp file that used to run with all of this code and I put it into the header file that you can see above so that I could template my functions.

I have noticed if I put #include "main.cpp in my header file that I get a ton more errors but the previous ones are gone. Now they are all errors for my main.cpp file like fractionType: undeclared identifier type float unexpected fraction1: undeclared indentifier fraction2: undeclared indentifier and it continues on in repeat for a total of 47 errors.

  • 3
    If you enable all compiler warnings, you should receive a warning about non-template friend declarations. That should provide a good clue as to the [problem](https://godbolt.org/z/MvG8rqc8j) and [solution](https://godbolt.org/z/Y98fM35Kx). – paddy Nov 08 '22 at 03:45
  • I believe it was due to me not including the main file in my header as I said in my post but I am still having the issue of undeclared identifiers and type 'float' unexpected etc. Could enabling all compiler warnings help with this as well? How do I enable all warnings as I am not sure how to do that in visual studio – 2Silent4You Nov 08 '22 at 03:50
  • Fixing undeclared identifiers should be straight forward. "Unexpected" errors are often due to a previous error, or a syntax error such as missing semicolon on a previous line. Read your code and read the errors carefully. Enabling all warnings is a good practice in general. `Project Properties > C/C++ > General > Warning Level` – paddy Nov 08 '22 at 03:59
  • I don't believe you have been banned by Google. – 273K Nov 08 '22 at 03:59
  • I have been pulling my hair out over this all day, when I saw the unexpected errors I figured they would be easy as I have dealt with them a lot I may just be overlooking but I just have no clue where this issue to coming from. I just tried all compiler warnings and everything is the exact same. – 2Silent4You Nov 08 '22 at 04:10
  • 1
    You should never ever `#include "main.cpp"`, so there's that. – n. m. could be an AI Nov 08 '22 at 04:31
  • That would lead me back to the initial error at the top of my post, got any ideas? – 2Silent4You Nov 08 '22 at 04:36
  • You've got that error explained in the very first comment. – n. m. could be an AI Nov 08 '22 at 06:39
  • I get `C4365 'argument': conversion from 'long' to 'unsigned int', signed/unsigned mismatch` I have tried to look at this before but I just don't understand what is happening. – 2Silent4You Nov 08 '22 at 20:05

0 Answers0