I am using template class type datatypes as arguments for a method of a class. In that method, I am calculating the difference of the arguments and printing it. This is just a sample code from the actual project.
Header.h
#ifndef Header_h
#define Header_h
#include <iostream>
#include "string.h"
template <class T>
class Student
{
public:
Student(T);
void calcDifference(int idx, T val1, T val2);
};
#endif
main.cpp
#include <iostream>
#include "Header.h"
using namespace std;
template <class T>
void Student<T>::calcDifference(int idx, T val1, T val2)
{
T difference = val1 - val2;
cout<<"\nDifference values: "<<difference<<endl;
}
template <class T>
Student<T>::Student(T)
{
cout<<"constructor called";
}
int main(int argc, const char * argv[])
{
Student<int> oStudent(10);
oStudent.calcDifference(1, 12, 10);
//THIS FOLLOWING OBJECT CREATES ERROR BECAUSE IT IS TRYING TO PASS STRING TYPE
Student<string> o2_Student("hi");
o2_Student.calcDifference(1, "aaa", "aa");
return 0;
}
Problem: As, I am trying to calculate the difference between the arguments inside the calcDifference()
, the second object in the main()
which is trying to pass strings creates problem. It is because the difference operation cannot be performed at strings (at least directly).
Error: /Users/siddharth/coding/cplusplus/xCode/CPPCodes/InterviewTest/InterviewTest/main.cpp:9:26: Invalid operands to binary expression ('std::__1::basic_string<char>' and 'std::__1::basic_string<char>')
What I need: I want that the code remain generic (for the calling function which I can't change acually). I want to find some solution so that I won't get this complier error and if the arguments passed are of string type then, the calcDifference()
should print the an statement (like "String datatype is not allowed") and return to the calling function. I can make changes inside the calcDifference()
ONLY because in the actual project I do not have control at the calling function. I think that exception-handling cannot help in this case because it is helpful to catch runtime error but in this case, I am getting compile time error as the calling function is trying to pass string (template T is made string).
PS: I cannot make any change in this structure which means that I cannot even change the number of arguments etc. I can only make changes inside the method calcDifference()
.
The line
T difference = val1 - val2;
is a problem when val1 - val2
is not defined for a type. That is the case when T = std::string
. That's what the compiler is complaining about.
One way to resolve the problem is to use a helper struct
template that will work for most types using a generic logic but will allow you to specialize it for types for which val1 - val2
is not defined.
Define a helper struct
template <typename T> struct difference
{
T operator()(T val1, T val2) const { return val1 - val2; }
};
Instead of using
T difference = val1 - val2;
use
T diff = difference<T>()(val1, val2);
Specialize difference
for std::string
.
template <> struct difference<std::string>
{
std::string operator()(std::string const& val1,
std::string const& val2) const
{
// Figure what it means to compute the difference
// between two strings for your application.
return stringDifference(val1, val2);
}
};