1

I was trying templates in CPP. I could not understand why 'Hello' is being printed when I compare it with 'World'?

Below is my code snippet ->

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
T max(T a, T b){
if(a > b){
return a;
}
else{return b;}
}

int main() {
  cout << "max(3, 5): " << max(3, 5) << endl;
  cout << "max('a', 'd'): " << max('a', 'd') << endl;
  cout << "max(\"Hello\", \"World\"): " << max("Hello", "World") << endl;
  return 0;
}

Output

ec2-user:~/environment/cpp_learn/uiuc_cpp/cpp-templates (master) $ make
g++ -std=c++14 -O0 -pedantic -Wall  -Wfatal-errors -Wextra  -MMD -MP -g -c  main.cpp -o .objs/main.o
g++ .objs/main.o -std=c++14  -o main
ec2-user:~/environment/cpp_learn/uiuc_cpp/cpp-templates (master) $ ./main 
max(3, 5): 5
max('a', 'd'): d
max("Hello", "World"): Hello

Here is the C++ version that I use ->

ec2-user:~/environment/cpp_learn/uiuc_cpp/cpp-templates (master) $ c++ --version
c++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Thanks in advance for your help. I apologize if the answer is too obvious.

HARSHIT BAJPAI
  • 361
  • 2
  • 17
  • 1
    Because the pointer happens to be larger than the other one. You’re not comparing contents of the strings, you’re comparing pointers. – Sami Kuhmonen May 17 '20 at 11:01
  • If pointers are being compared, then can I use a dereference symbol '*' for comparing the actual value? Something like - if(*a > *b){ return a; } – HARSHIT BAJPAI May 17 '20 at 11:16
  • You could, but then you’d compare only the first character, which probably isn’t what you want – Sami Kuhmonen May 17 '20 at 11:22

2 Answers2

2

Both "Hello" and "World" are c-style strings (with type const char[6]), when being passed to max they decay to const char*, and T is deduced as const char* too. So the comparasion is just comparing the pointer, i.e. memory address, the reuslt is unspecified.

You can add overload or template specialization using strcmp to compare c-style strings, or use std::string instead,

my_max(std::string("Hello"), std::string("World")) // name changed because of the conflict with std::max 
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Thanks for your response. I don't understand why is memory address of 'Hello' greater than 'World' always and memory address of 'a' is less than 'd' always? I also tried passing 'World' first but the output is still same. – HARSHIT BAJPAI May 17 '20 at 11:10
  • Also, I tried your change. It gives a compiler error - main.cpp:23:90: error: call of overloaded ‘max(std::string, std::string)’ is ambiguous cout << "max(\"World\", \"Hello\"): " << max(std::string("Hello"), std::string("World")) << endl; – HARSHIT BAJPAI May 17 '20 at 11:11
  • @HARSHITBAJPAI For `char`s the value is compared (not member address), so `'d'` is returned. The result of comparing member address like this case is unspecified. – songyuanyao May 17 '20 at 11:16
  • @HARSHITBAJPAI About the compiling error, the name conflict with `std::max`. Changing the name would be fine. [LIVE](https://wandbox.org/permlink/Dkt6IkaBiQN8AnTh) – songyuanyao May 17 '20 at 11:16
1

Instead, you can use two templates T and P for the same.

#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
template <typename T,typename P>
T max(T a, P b){
if(a > b){
return a;
}
else{return b;}
}

int main() {
  cout << "max(3, 5): " << max(3, 5) << endl;
  cout << "max('a', 'd'): " << max('a', 'd') << endl;
  cout << "max(\"Hello\", \"World\"): " << max(string("Hello"),string("World")) << endl;
  return 0;
}

Compile this modified version. This code is self-explanatory.

Aurora087
  • 86
  • 5
  • Thanks for this. Why the use of 2 typenames though? – HARSHIT BAJPAI May 17 '20 at 12:09
  • @HARSHITBAJPAI If you want to use the name `max` because it was conflicting with the inbuilt max. Using two type names is useful when we have to play with multiple data types like `sum(string("10.5"),'c')` if we use the same template this won't work. – Aurora087 May 17 '20 at 12:40
  • 1
    Please don't [`#include `](https://stackoverflow.com/q/31816095/9254539). – eesiraed May 17 '20 at 19:01