17

I'm following the pluralsight C++ course, and in it is the following code:

#include <iostream>

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

int main()
{
    std::cout << "Max of 33 and 44 is " << max(33, 44) << std::endl;

    return 0;
}

I typed over this piece of code, but unlike the code of the course, I get an error message:

C2664: 'max' : cannot convert parameter 1 from 'int' to 'int &'

The code in the course is written in Visual Studio Express 2010, while mine is written in Visual Studio Ultimate 2010.


EDIT

Thanks to everybody (even Kate Gregory herself) for providing answers and clearing everything up.

Garth Marenghi
  • 1,997
  • 5
  • 20
  • 38
  • Do you have a link to the course, and is that the _exact_ code from the course? – James McNellis Nov 25 '12 at 21:16
  • The course is called Pluralsight C++ fundamentals, the first part. It is the exact code. There is also code that uses max with strings and a user defined class, but it doesn't have anything to do with the integers being passed into max, just showing the functionality of max. – Garth Marenghi Nov 25 '12 at 21:22

7 Answers7

33

Because literals (and rvalues in general) cannot be passed by non-const reference (since it would make no sense if the callee could change them). Either pass by value or by const reference:

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

or

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

Both 33 and 44 are rvalues; they're passed to the function by value and not by reference. The compiler can't convert these two to the expected type int &. Use variables (lvalues) as they can be passed by reference:

int a = 33, b = 44;

max(a, b); // 44

Since you're merely dealing with fundamental types here (int), passing by reference is redundant. Passing by value causes a copy, but the difference will be negligible:

template <class T>
T max(T t1, T t2);

Here we can pass both rvalues and lvalues. But there is the chance that you could pass in a object of class type. In that case passing by reference is recommended.

But for the case where we don't want a copy and want both lvalues and rvalues, we can pass by const reference:

template <class T>
T max(T const &t1, T const &t2);

In C++11 you can pass the arguments by a universal-reference so that we can bind glvalues:

template <class T>
T max(T&& t1, T&& t2);

int main()
{
    int a{0}, b{0};

    max(a, b);
    max(1, 2);
}

If you want to keep the lvalue-reference syntax in your original code, you can use this lvalue shim:

template<typename T>
T& lvalue(T&& t)
{
    return t;
}

int main()
{
    max(lvalue(1), lvalue(2));
}
David G
  • 94,763
  • 41
  • 167
  • 253
4

The answer here turns out to lie in the unrelated code you didn't use in your test. Absolutely my little max() should take either by value, or const-ref, and that was just a brain-slip that I will fix as soon as I can.

But the full demo code works beautifully. That's because it includes more headers, one of which brings in xutility and therefore std::max. This led me to not notice that my max wasn't being used. I'll redo the demo with a name like biggest to eliminate that happening again. And in the meantime, yes, if you want to pass literals to a function by reference, they need to be const ref. I knew that, but didn't think of it while writing the test harness, and then was fooled when bad code appeared to work. I should have re-read the code more carefully: thanks for calling this to my attention. (And thanks for taking the course and I hope you're finding it helpful.)

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
  • 1
    :-) Thanks a lot for your response! And yes, I find the course helpful. I've been using C# for some years, and always wanted to try C++ but was... fearful? The course just let me slip in easily. – Garth Marenghi Nov 25 '12 at 21:57
  • 1
    The problem of accidentally calling `std::max` instead of your own `max` is only possible with a `using namespace std;` somewhere in your own code. [We know this is a very bad idea](http://stackoverflow.com/questions/1452721/). Shame on you! ;) – fredoverflow Nov 25 '12 at 22:25
  • 1
    :-) it is a bad idea in a header file - this goes to show it can bite you in a .cpp file too. – Kate Gregory Nov 25 '12 at 22:27
3

You can't pass temporary value as T&. Since you don't change arguments, use const T& instead

BTW, there is built-in max function

RiaD
  • 46,822
  • 11
  • 79
  • 123
3

Integer literals cannot be passed as non-const reference. Besides, your max function can work with const references, so mark them appropriately:

T max(const T& t1, const T& t2)
Maciek
  • 1,696
  • 12
  • 19
2

If you defined your function with parameters by reference, you cannot use anything but variable names for said parameters - and you try to use numbers.

mvp
  • 111,019
  • 13
  • 122
  • 148
2

Small remark. You can use your initial code of function "max". Try change call from max(34, 44) to max<const int>(34,44). Sometime it can be useful.

#include <iostream>

template <class T>
T max(T& t1, T& t2)
{
   return t1 < t2 ? t2 : t1;
}
int main()
{
   std::cout << "Max of 33 and 44 is " << max<const int>(33, 44) << std::endl;
   return 0;
}
SergV
  • 1,269
  • 8
  • 20