0

I know there are several answers similar to this question already but I think my lack of experience in C++ is preventing me from understanding them fully.

Problem: I have an assignment where I need the user to enter a value which should be of type 'double'. I then need to pass that user input into a custom method for a class I created and have the method validate that this input is indeed a 'double'.

I saw several posts where people validated the data type right after it was entered using a while loop and the cin operator. This doesn't help me because I need to validate the data type in the method.

Here is what I have so far:

Main.cpp:

...
int main() {

    string name;
    double gpa;   // value that should be validated

    cout << Enter GPA: ";
    cin >> gpa;

    myClass student_1;
    student_1.validateGPA(gpa); 

    return 0;
}

myClass.h

...

template <class validation>
void validateGPA(validation);

myClass.cpp

...

template <class validation>
string myClass::validateGPA(validation gpa) {
    return typeid(newGPA).name();
} 

As written currently I am receiving this Error:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall myClass::validateGPA<double>(double)" (??$validateGPA@N@myClass@@QAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@N@Z) referenced in function _main    GPA_Assignment  C:\Users\josep\source\repos\ccv\GPA\GPA\GPA_Assignment.obj  1   

Without templating the function, the program ran but no matter what I entered at the prompt, the validation method always returned 'double'. I am assuming that is bc of how I declared the gpa varaible in the beginning, but I don't know a better way.

Thoughts!??

Joe
  • 2,641
  • 5
  • 22
  • 43
  • 1
    Does this answer your question? [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) – AVH Nov 01 '20 at 15:45
  • The linker error you're getting is indeed related to it being a templated function, see [here](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). As far as the function returning incorrect values, note that the function's argument is `gpa` but you return `typeid(newGPA)`. what's `newGPA`? ETA: Not that it's going to be relevant because `main` guarantees that whatever the user inputs, you hand a `double` to the `validateGPA` function. – Nathan Pierson Nov 01 '20 at 15:45
  • You don't "check data types" in C++. You validate user input. You say `double gpa`, it's `double`, there's nothing to check. – n. m. could be an AI Nov 01 '20 at 15:45
  • @NathanPierson `newGPA` is the gpa variable, just a transposition error putting the question up – Joe Nov 01 '20 at 15:48
  • @n.'pronouns'm. What if the user enters a string instead of a double? When i do that in my code it works. The code prints the string out but that is not what I am looking for. – Joe Nov 01 '20 at 15:49
  • If you want to defer input validation to the actual class itself, I suggest storing the user input in a `std::string` instead of a `double` in `main` and then doing the type conversion in a class method. – Nathan Pierson Nov 01 '20 at 15:52
  • User input cannot magically change the type of `gpa`. The user can pound on the keyboard all day long and `gpa` will stay `double`. Variables in C++ don't change their types. What can happen depending on user input is that `cin >> gpa` can either *succeed* or *fail*, and you are supposed to check *that*. – n. m. could be an AI Nov 01 '20 at 15:53
  • @n.'pronouns'm. Maybe the better way to phrase this would be how do I validate user input in the method instead of the main – Joe Nov 01 '20 at 15:55
  • @NathanPierson That sounds like it may work. If the user entered a string and I tried to convert to a double would I receive some error that may help or would it just convert it to double no issue? – Joe Nov 01 '20 at 15:56
  • You can do what you want in any place in the code you want. You just need to check the right thing. `typeid` isn't one. – n. m. could be an AI Nov 01 '20 at 15:57
  • Maybe try search. Does [this](https://stackoverflow.com/search?q=validate+input+double+%5Bc%2B%2B%5D) help? – n. m. could be an AI Nov 01 '20 at 16:04
  • @n.'pronouns'm. I have already spent a couple hours playing that search game. You'll notice that most of the result (that I can make sense of) use a CIN validation technique, which I mentioned in my question does not work for me' – Joe Nov 01 '20 at 16:05
  • "does not work for me" It doesn't make a lot of sense. You can do `cin >>` in a method. Why would it not work for you? – n. m. could be an AI Nov 01 '20 at 16:11
  • @n.'pronouns'm. I guess my confusion is that I didn't think I could pass cin through the method. But reading your comment it sounds like maybe I should be calling cin from the method and then validate there. Does that sound like a good solution? – Joe Nov 01 '20 at 16:13
  • `cin` is global, there's no need to pass it. It's an OK solution. What would you do if the input doesn't validate? – n. m. could be an AI Nov 01 '20 at 16:19
  • @n.'pronouns'm. I think I have it working using cin in the method. If it doesn't validate I just need to return a message saying that it was invalid. Thanks for the help, I think by calling cin in the method I can use the user validation examples here on stack and move forward! This has been a big headache this morning! – Joe Nov 01 '20 at 16:21

1 Answers1

0

std::cin is an input stream. To get formatted data from input, you can use the operator it defines: >>. If you put the input stream on the left hand side and a variable that has a type that it recognizes on the right hand side, cin will read to the end of its input and try to parse that into whatever data type is on the right hand side. Lucky for you, the operator does support double. Therefore, to read the input (a string) and convert it into a decimal number (a double), you can just write

double converted_number;
cin >> converted_number;

According to the documentation, you can validate the formatted input by checking the value of cin.rdstate(). Let's add that.

double converted_number;
cin >> converted_number;

if(cin.rdstate() != goodbit) {
    cout << "A decimal number was expected, but an error occurred.\n";
    return 0;
}

Make sure to include the ios header at the beginning of your file if you haven't already.

#include <ios>

The error comes from the linker. It stems from the way you define your function template. You don't need it to be a template though. Just use a regular function. I feel the explanation for that is outside the scope of this question, so I'll just leave it at that.

James King
  • 88
  • 1
  • 3