shashu10
shashu10

Reputation: 303

template function - type checking error - c++

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

Answers (4)

Andrew Durward
Andrew Durward

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

Seth Carnegie
Seth Carnegie

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

Adrian Cornish
Adrian Cornish

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

Sergey Kalinichenko
Sergey Kalinichenko

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

Related Questions