2

I was trying out a sample generic function in C++ , the code follows:

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

template <typename T>
T max(T a, T b){
    return (a>b)?a:b;
}

int main()
{
    int a=2,b=4;
    float af = 2.01,bf=2.012;
    double ad = 2.11,bd=1.22;
    cout<<max(a,b);
}

I am getting the error as

main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
     cout<<max(a,b);
                  ^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
 T max(T a, T b){
   ^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
     cout<<max(a,b);
                  ^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
 T max(T a, T b){
   ^main.cpp: In function ‘int main()’:
main.cpp:20:18: error: call of overloaded ‘max(int&, int&)’ is ambiguous
     cout<<max(a,b);
                  ^
main.cpp:20:18: note: candidates are:
main.cpp:9:3: note: T max(T, T) [with T = int]
 T max(T a, T b){
   ^

What am I doing wrong here ?
What is meant by call of overloaded max(int&, int&) is ambiguous ?
Why am I getting its argument shown as & where as there was no such syntax defined by me above ?

7
  • There is already a built-in function called max. Try a different name. Commented Aug 23, 2016 at 5:48
  • 4
    And that's exactly the reason why using namespace std; is discouraged. Commented Aug 23, 2016 at 5:50
  • yeah that worked for me :) , can you explain me where is it defined ? Commented Aug 23, 2016 at 5:50
  • 1
    @vu1p3n0x: note that even if you just #include <iostream> there is a possibility that std::max is being defined. The standard include algorithm is where for sure it is defined, but dependencies between standard headers is unspecified. After you include any standard header all of the other names could have potentially been included in std namespace. Commented Aug 23, 2016 at 6:00
  • @Rakete1111: what is not clear is why C++ forces programmers to use #include directives for the standard library, wasting precious neurons to remember what include formally defines what names. Commented Aug 23, 2016 at 6:02

3 Answers 3

8

The problem is that C++ already has a std::max definition.

Pick another name and everything should be fine.

In C++ the using namespace std approach is a bad idea as thousands of names will be injected. Just get the habit of typing std:: in front of standard names.

Remember also that saving time when writing is not really that important, what is important is saving time when reading (normally code is written just once but read and understood many times).

std:: in front of standard names actually speeds up reading and lets understanding on the spot that what is being used is part of the standard library (not everyone knows the whole standard library by heart).

Sign up to request clarification or add additional context in comments.

Comments

3

Skypjack and 6502's answers are spot on so I won't go over that here.

It is also worth noting that the standard's version of max is not that clever. You can cause it not to compile with code like this:

int main()
{
  int a = 0;
  double b = 1;
  auto c = std::max(a, b);
}

yields error message:

16 : error: no matching function for call to 'max(int&, double&)'

If we wanted to rewrite max, we might imagine that we were improving it by writing it this way:

#include <type_traits>

namespace notstd {
  template <typename T1, class T2>
  auto max_any(T1 a, T2 b) -> std::common_type_t<T1, T2>
  {
    return (a>b) ? a : b;
  }
}

int main()
{
  int a = 0;
  double b = 1;
  auto c = notstd::max_any(a, b);
}

But of course there would be some consequences.

Firstly, max_any is now forced to take copies and (possibly) perform conversions. For integers and doubles this is almost not worth mentioning.

But if T1 and T2 were two classes of object that had appropriate conversion operators, calling max_any on them could potentially be an expensive operation. It might also have material side-effects.

For this reason, std::max is defined in terms of arguments of type T&. It forces the caller to perform the conversion. It turns out that this is not a limitation of std::max. It is a safety feature.

The function does not inject any hidden side-effects into your code.

In order to maintain 'the path of least surprise' in its behaviour, the standard library sometimes requires that its users spell out the surprising behaviour that they want.

Example of surprising behaviour

This program will compile perfectly:

#include <cstdlib>
#include <iostream>

namespace notstd {
  template <typename T1, class T2>
  auto max_any(T1 a, T2 b)
  {
    return (b < a) ? a : b;
  }
}

struct A {
  A() = default;
};

struct B {
  B() = default;
  B (A const&) { std::exit(100); }
};

bool operator<(B const&, A const &) { return true; }

int main()
{
  A a;
  B b;
  auto c = notstd::max_any(a, b);
  std::cout << "Hello, World\n";
}

But it will never print "Hello, World".

Someone maintaining this code might be surprised to learn that.

2 Comments

Few Questions 1. why would it not print "Hello World" ? 2. what does A()=default ; statement mean??
@KapilBhandari A() = default; declares a default constructor with a default implementation. It's valid as of c++11. To find out why the program does not print "Hello, World", compile it, single-step and see... :)
2

There exists already a max function in the standard template library (namely std::max).
Using the using namespace directive, you are importing the names from the std:: namespace to the one in which you are using the declaration itself.
You can still use the following line to pick your implementation of max:

cout  <<  ::max(a,b);

Otherwise, as someone already mentioned, you can choose a different name for your function or use directly the one fron the standard template library.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.