4

I'm not quite sure why the answer for the larger string ("cat" and "dog") is not consistent. I was doing some things with Linked Lists and the use of templates. My curiosity got me to revise templates and function overloading. If anyone can explain what is going on, I would appreciate it. Thank you.

#include <iostream>
using namespace std;   // for the sake of simplicity. (otherwise, std::)

// Function overloading and the use of templates

// overloading the function larger
int larger(int, int);
char larger(char, char);
double larger(double, double);
string larger(string, string);

template <class elementType>
elementType anyLarger(elementType parameter1, elementType parameter2);


int main() {

    cout << endl;
    cout << "Function Overloading" << endl;

    cout << "larger(15, 27)            =  " << larger(15, 27) << endl;
    cout << "larger('X', 'P')          =  " << larger('X', 'P') << endl;
    cout << "larger(4.9, 3.2)          =  " << larger(4.9, 3.2) << endl;
    cout << "larger(cat, dog)          =  " << larger("cat", "dog") << endl;

    cout << endl;
    cout << "Using the function template to find the larger of two items" << endl;
    cout << "anyLarger(15, 27)         =  " << anyLarger(15, 27) << endl;
    cout << "anyLarger('X', 'P')       =  " << anyLarger('X', 'P') << endl;
    cout << "anyLarger(4.9, 3.2)       =  " << anyLarger(4.9, 3.2) << endl;
    cout << "anyLarger(cat, dog)       =  " << anyLarger("cat", "dog") << endl;
    cout << endl;


    cout << "Compare two strings:   cat, dog" << endl;
    if ("cat" >= "dog") {
      cout << "cat is greater than dog" << endl;
    }
    else {
      cout << "dog is greater than cat" << endl;
    }

    cout << endl;
    string strCat = "cat";
    string strDog = "dog";
    cout << "string strCat = cat" << endl;
    cout << "string strDog = dog" << endl;
    if (strCat >= strDog) {
      cout << "strCat is greater than strDog" << endl;
    }
    else {
      cout << "strDog is greater than strCat" << endl;
    }
    cout << endl;
} // end main 

// Overloading larger
int larger(int x, int y) {
    if (x >= y)
      return x;
    else 
      return y;
}

char larger(char a, char b) {
    if (a >= b)
      return a;
    else 
      return b;
}

double larger(double p, double q) {
    if (p >= q)
      return p;
    else
      return q;
}

string larger(string y, string z) {
    if (y >= z)
      return y;
    else
      return z;
}


// Defining the template function
template <class elementType>
elementType anyLarger(elementType parameter1, elementType parameter2)
{
    if (parameter1 >= parameter2)
      return parameter1; 
    else
      return parameter2;
}

Here is the result after running the program.

Function Overloading
larger(15, 27)            =  27
larger('X', 'P')          =  X
larger(4.9, 3.2)          =  4.9
larger(cat, dog)          =  dog

Using the function template to find the larger of two items
anyLarger(15, 27)         =  27
anyLarger('X', 'P')       =  X
anyLarger(4.9, 3.2)       =  4.9
anyLarger(cat, dog)       =  cat

Compare two strings:   cat, dog
cat is greater than dog

string strCat = cat
string strDog = dog
strDog is greater than strCat

==============================================

Update: Made some changes and used strcmp

#include <iostream>
#include <string.h>
using namespace std;

// Function overloading and the use of templates


// overloading the function larger
int larger(int, int);
char larger(char, char);
double larger(double, double);
string larger(string, string);


template <class elementType>
elementType anyLarger(elementType parameter1, elementType parameter2);


int main(){

  cout << endl;
  cout << "// Function Overloading" << endl;


  cout << "larger(15, 27)              =  " << larger(15, 27) << endl;
  cout << "larger('X', 'P')            =  " << larger('X', 'P') << endl;
  cout << "larger(4.9, 3.2)            =  " << larger(4.9, 3.2) << endl;
  cout << "larger(\"cat\", \"dog\")        =  " << larger("cat", "dog") << endl;

  cout << endl;
  cout << "// Using the function template to find the larger of two items" << endl;
  cout << "anyLarger(15, 27)           =  " << anyLarger(15, 27) << endl;
  cout << "anyLarger('X', 'P')         =  " << anyLarger('X', 'P') << endl;
  cout << "anyLarger(4.9, 3.2)         =  " << anyLarger(4.9, 3.2) << endl;
  cout << "anyLarger(\"cat\", \"dog\")     =  " << anyLarger("cat", "dog") << endl;
  cout << endl;


  cout << "// Compare two strings using >= :   \"cat\", \"dog\"" << endl;
  if ("cat" >= "dog") {
    cout << "\"cat\" is greater than \"dog\"" << endl;
  }
  else {
    cout << "\"dog\" is greater than \"cat\"" << endl;
  }

  cout << endl;
  cout << "// The use of variables: strCat and strDog. Compare using >=" << endl;
  string strCat = "cat";
  string strDog = "dog";
  cout << "string strCat = \"cat\";" << endl;
  cout << "string strDog = \"dog\";" << endl;
  if (strCat >= strDog) {
    cout << "strCat is greater than strDog" << endl;
  }
  else {
    cout << "strDog is greater than strCat" << endl;
  }
  cout << endl;


  cout << "// Using strcmp.   strcmp(\"cat\", \"dog\")" << endl; 
  int result = strcmp("cat", "dog");
  if (result > 0) {
    cout << "\"cat\" is greater than \"dog\"" << endl;
  }
  else {
    cout << "\"dog\" is greater than \"cat\"" << endl;
  }
}

// Overloading larger
int larger(int x, int y) {
if (x >= y)
    return x;
  else 
    return y;
}


char larger(char a, char b) {
  if (a >= b)
    return a;
  else 
    return b;
}


double larger(double p, double q) {
  if (p >= q)
    return p;
  else
    return q;
}

string larger(string y, string z) {
  if (y >= z)
    return y;
  else
    return z;
}


// Defining the template function
template <class elementType>
elementType anyLarger(elementType parameter1, elementType parameter2)
{
  if (parameter1 >= parameter2)
    return parameter1; 
  else
    return parameter2;
}

================

Update: Output

// Function Overloading
larger(15, 27)              =  27
larger('X', 'P')            =  X
larger(4.9, 3.2)            =  4.9
larger("cat", "dog")        =  dog

// Using the function template to find the larger of two items
anyLarger(15, 27)           =  27
anyLarger('X', 'P')         =  X
anyLarger(4.9, 3.2)         =  4.9
anyLarger("cat", "dog")     =  cat

// Compare two strings using >= :   "cat", "dog"
"cat" is greater than "dog"

// The use of variables: strCat and strDog. Compare using >=
string strCat = "cat";
string strDog = "dog";
strDog is greater than strCat

// Using strcmp.   strcmp("cat", "dog")
"dog" is greater than "cat"
User_fts
  • 55
  • 6
  • I believe anyLarger and "" string comparison compares `char*`, while larger and string variables compares `std::string`'s – EvgeniyZh Dec 11 '15 at 21:21

5 Answers5

10

You are not lexicographically comparing strings in both cases.

"cat" >= "dog"

This is comparing char pointers because the type of the literals "cat" and "dog" is const char*. It could give either result, depending on how the compiler decided to materialize the literals.

To lexicographically compare C-style strings (including literals like these) the function strcmp must be used instead.

strCat >= strDog

This is comparing strings lexicographically because std::string provides comparison operators that explicitly implement this kind of comparison.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 2
    Heck, it could give [both results](https://markshroyer.com/2012/06/c-both-true-and-false/) since it's undefined behaviour to compare (excluding (in)equality) two "unrelated" pointers. – chris Dec 11 '15 at 21:24
  • @chris: Hehe, so true. – Jon Dec 11 '15 at 21:25
  • 1
    Technically, the type of the literals `"cat"` and `"dog"` is `const char[4]`, and can be implicitly converted to `const char*`. – IInspectable Dec 11 '15 at 21:38
  • @chris: correct. `std::greater`, on the other hand, does provide a total order (but it's still unpredictable). – rici Dec 11 '15 at 21:53
  • Jon, thank you very much. I recently saw something about lexicographically comparing strings. Do you know/have any references/tutorials that you might be able to point me to? – User_fts Dec 11 '15 at 22:48
4
"cat" >= "dog"

You are comparing pointers but not the actual values. Use strcmp.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
4

That's because string literal (e.g. "cat") isn't of type std::string. You're doing a pointer comparison on two unrelated arrays of const char.

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
3

The literal string "cat" and "dog" are actually pointers to arrays of characters when you come to compare them, so the greatest will be the one that happens to be stored in memory at a higher location.

Your string larger(string y, string z) works because std::string can be constructed from a char* and so "cat" and "dog" get converted to std::string objects before being compared.

The template function, on the other hand, accepts them as their actual types which, when passed as parameters, become const char* and only their addresses get compared.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • Thank you for explaining. Based on your explanation and a look at the ASCII table (Dec for d = 100, and Dec for c = 99), it would be correct to say that the template function gives an "incorrect" answer, right? – User_fts Dec 11 '15 at 22:41
  • @User_fts The template function simply doesn't do what you think it does. It doesn't compare the strings. It compares their position in memory. Every variable is stored in memory at a specific location and that location is referred to by a number. Your template function compares those numbers. – Galik Dec 11 '15 at 22:53
  • Galik, thank you. That makes sense. if you would use a single template function that would work for int, double, char and string, how would you implement it? (the template function Prazuber wrote would work when you need to compare using strcmp) – User_fts Dec 12 '15 at 16:35
  • @User_fts If you want it to accept string literals like `"cat"` then you can't do it just with a template function. @prazuber's answer has a solution. – Galik Dec 12 '15 at 16:52
  • Galik. Sounds good. You're very knowledgeable with the C++ language, what has been the most useful resource or way of learning for you? If you can't discuss that on here, based on the type of questions permitted, would you mind if I reach you in another means? – User_fts Dec 12 '15 at 17:37
  • @User_fts I would recommend working methodically through a good book, bring any problems to this forum. Don't just get any book because there are so many bad books. I suggest choosing from this list: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list Also, if you have [IRC](https://webchat.freenode.net/) you can chat/lurk in Freenode's `##c++`, `##c++-basic` & `##c++-general`. – Galik Dec 12 '15 at 17:52
  • Thank you very much, Galik. I appreciate your suggestions and comments. – User_fts Dec 12 '15 at 18:08
3

As others have already mentioned, in your line

cout << "anyLarger(cat, dog)       =  " << anyLarger("cat", "dog") << endl;

you are invoking anyLarger<const char &[]>, i.e. you call anyLarger with string literal arguments, which indeed boils down to comparing pointers instead of strings. You can fix this by either calling your function with std::string arguments by one of the following lines:

larger("cat", "dog");
anyLarger<std::string>("cat", "dog");
anyLarger(std::string("cat"), std::string("dog"));
anyLarger("cat"s, "dog"s); // C++14

or you could do a template specialization for string literals (or just any C-type strings, whatever you choose):

template <>
elementType anyLarger<char*>(char* parameter1, char* parameter2)
{
    if (strcmp(parameter1, parameter2) >= 0)
      return parameter1; 
    else
      return parameter2;
}
prazuber
  • 1,352
  • 10
  • 26
  • Thank you, Prazuber. I like your implementation for the template function. In my update, the use of strcmp produced "dog" as being greater. Running your version should produce "dog" I would give it another shot. – User_fts Dec 11 '15 at 22:45