Reputation: 303
I have this function template
template < class TParam >
bool greaterThan (TParam A, TParam B) {
if (typeid(TParam) == typeid(string)) {
return A.compare(B) > 0; <--------------- Error
} else {
return A > B;
}
}
But the compiler won't allow me to use this with an int
.
I get a compiler error in the place shown above that says
Member reference base type 'int' is not a structure or union.
The if statement does not run if I'm calling the function on an int
.
I commented it out and checked. I don't know whats wrong.
Upvotes: 1
Views: 874
Reputation: 3861
Calling a template function causes the compiler to instantiate the whole function and the statement causing the error obviously doesn't work for int
parameters. There are a couple of ways to separate the two cases:
First, using a specialization of greaterThan
for strings:
template < class TParam >
bool greaterThan (TParam A, TParam B) {
return A > B;
}
template<>
bool greaterThan< string > (string A, string B) {
return A.compare(B) > 0;
}
Second, using an overload of greaterThan
for strings:
template < class TParam >
bool greaterThan (TParam A, TParam B) {
return A > B;
}
bool greaterThan (string const & A, string const & B) {
return A.compare(B) > 0;
}
In both options, the decision of which function to call is made at compile time as opposed to checking the type at runtime. Note however that the overload accepts the parameters by reference whereas the specialization accepts the parameters by value since it must match the signature of the base template function exactly.
Also, with specializations the function chosen by the compiler can sometimes be unexpected. And since function templates can only be explicitly specialized (i.e. not partially specialized), overloading offers all of the benefits and none of the drawbacks associated with specializations.
See "Why Not Specialize Function Templates?" by Herb Sutter for more information.
Upvotes: 1
Reputation: 75130
When TParam
is int
, with this:
A.compare(B)
You're trying to call the compare
method of an int
. Such a method does not exist. What you need is template specialisation so that you can make the template do something special when the type is a certain type:
template<class TParam>
bool greaterThan(TParam A, TParam B) {
return A > B; // this will be called for any type except string because of
// our following specialisation
}
// make a specialisation for when the template parameter is string
template<>
bool greaterThan<string>(string A, string B) {
return A.compare(B) > 0;
}
The syntax is a tiny bit foreign but if you read up on it, template specialisation is a very powerful addition to templates.
Note that string
does have operator<
so you don't even need to specialise it if you don't want to, but this is a good opportunity to learn about template specialisation.
Upvotes: 2
Reputation: 23858
Template code is generated at compile time so the if() statement has not been executed yet.
There are 2 solutions to this
a) provide a specialized version of the template for int's
b) Don't use Compare() - and make it a requirement that struct/classes provide a comparison operator.
Upvotes: 1
Reputation: 726489
You know that you are not calling compare
on an int
, but the compiler does not: your if
is evaluated at run-time.
Since string
is the only special case in your template, try this:
template < class TParam >
bool greaterThan (TParam A, TParam B) {
return A > B;
}
bool greaterThan(const string& a, const string& b) {
return a.compare(b) > 0;
}
Upvotes: 2