0

I'm watching a tutorial where Kate Gregory creates the function:

template <class T>
T max(T& t1, T& t2)
{
  return t1 < t2 ? t2 : t1;
}

and has the following code in main():

cout << "max of 33 and 44 is: " << max(33,44) << endl;

She compiles and runs it in VC++ Express 2010 without complaints.

I tried the same code in VC++ 2013 Community and it fails because it can't find a max template that takes (int, int).

I corrected the max function to take the arguments (T const& t1, T const& t2) instead and everything works.

My question is: is this version-specific or is there a compiler option or setting that allows you to pass literals as non-constant ref arguments?

The only way I could coerce the code to work otherwise is by adding a reference to <algorithm> which obviously calls another (correct) version of max. Her includes aren't shown in their entirety in the screen-recording so I guess she could have 'cheated' for the sake of simplicity since she hadn't bought up const& yet, but I would be surprised.

carlsb3rg
  • 752
  • 6
  • 14

1 Answers1

2

Non-const lvalue references do not bind to rvalues (including all literals except string literals). This (properly) refuses to compile even in MSVC 2010:

#include <iostream>

using namespace std;

template <class T>
T max(T& t1, T& t2)
{
  return t1 < t2 ? t2 : t1;
}

int main(int argc, char* argv[])
{
    cout << "max of 33 and 44 is: " << ::max(33,44) << endl;
                                     //^^
    return 0;
}

The scope resolution operator :: forces the compiler to attempt to use the max you defined in the global namespace.

In fact, the following code compiles with GCC/libstdc++ and Clang/libc++ (at least the version on Coliru at the time of this writing):

#include <iostream>

using namespace std;

template <class T>
T max(T& t1, T& t2)
{
  return t1 < t2 ? t2 : t1;
}

int main(int argc, char* argv[])
{
    cout << "max of 33 and 44 is: " << max(33,44) << endl;
    return 0;
}

The issue is that <iostream> in those compilers/standard libraries (and MSVC 2010) also pulled in std::max, which ends up getting called due to the using namespace std;. MSVC 2013's <iostream> apparently doesn't pull in std::max, so you get an error.

There is an evil MSVC extension that allows non-const lvalue references to bind to rvalues, but that apparently doesn't cover primitive types like int.

T.C.
  • 133,968
  • 17
  • 288
  • 421