1

I'm following an online course (Pluralsight.com) in C++ and struggling with an exercise on templates, in particular passing an actual number (e.g. 3) to a template which expects (T& t).

The code written by the instructor will not compile on my PC - I believe I understand why it will not compile, but want to how it compiled for the instructor (who demos it) and how you should handle this case.

#include "stdafx.h"
#include <iostream>

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

int main()
{
    int result = myMax(3, 4);
    return result;
}

EDIT: Fixed typo in code (from my experimenting before asking the question). It seems to run in https://ideone.com/1cjJUD so I'm now not sure why it won't compile for me! (Thanks @user4581301)

EDIT2 Post-answer, change name of function to avoid confusion. Should make question clearer to anyone else who stumbles upon the same thing. https://ideone.com/dZffn6

The compiler error is "C2664 'T max<int>(T &,T &)': cannot convert argument 1 from 'int' to 'int &" This looks to me like it is failing since 3 is an actual number not a reference to a number stored somewhere. Declaring int a=3; and passing a to my max function works fine.

  1. Am I correct about the reason for the compile failure?
  2. How does the instructors code compiles without error? Has this changed in more recent C++ versions (I believe the class uses C++03)?
  3. Is it possible to write a template where I can pass either ByRef or ByVal? Would I end up with 4 cases (a, b); (a&, b); (a, b&); (a&, b&) ?
David258
  • 697
  • 2
  • 6
  • 15
  • @juanchopanza - Apologies - I made a mistake when copying the code and formatting - it should be fixed now. – David258 Sep 29 '17 at 22:10
  • @NeilButterworth - I think that's unhelpful; this sort of question could just as easily arise from reading a textbook as doing an online course. I have now fixed the code in the question, but my question still stands. – David258 Sep 29 '17 at 22:13
  • As for why this might compile: the instructor might be using non-standard Visual C++ features. In this case, at least in older versions of the compiler, Visual C++ had lifetime extension for non-const refs, not just const refs. – Justin Sep 29 '17 at 22:14
  • How does the instructor get it to run? Well, bad code or not, g++ seems to like it. https://ideone.com/1cjJUD – user4581301 Sep 29 '17 at 22:17
  • @Justin - That sounds possible, the course is a few years old now. Do you have any documentation/further links I could look up as I'm pretty new and don't know the nuances of C++? – David258 Sep 29 '17 at 22:17
  • @NeilButterworth - it seems that the code does compile here: https://ideone.com/1cjJUD I remain confused, I have an idea about why it will not compile locally - as written in the post. Are you able to help? – David258 Sep 29 '17 at 22:22
  • 2
    It's picking up the wrong max - get rid of the `using` directive, and you will see an error. –  Sep 29 '17 at 22:23
  • @NeilButterworth Removing the `using namespace std;` and the print line and I still get the same compiler error? https://ideone.com/dZffn6 – David258 Sep 29 '17 at 22:27
  • 1
    It's supposed to be an error! The code is wrong! –  Sep 29 '17 at 22:29
  • 4
    No. @Neil was explaining why GCC could eat that bad code: It wasn't. it was using `std::max`, not `max`. Another strike against `using namespace std;` – user4581301 Sep 29 '17 at 22:29

1 Answers1

3

Because you are returning by value, there's no reason for the parameters to be non-const. rvalues (including literals and temporary objects) are compatible with const references. So that would be a good way to fix it without dealing with all possible combinations:

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

Note that I've renamed the function to avoid ambiguity with std::max. Neil mentioned removing the using namespace std; in a comment -- while that line does trigger the problem, removing it is not a complete solution.

In particular, even without using namespace std;, the code std::complex<double> a, b; auto c = max(a, b); will still find std::max, defeating the whole purpose of making your function a template so it works with any type! This is a consequence of "argument dependent lookup".

So using a different name is the best option.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thanks - this was exactly the sort of answer I was hoping for. I can see why using const refs makes sense in this context. – David258 Sep 29 '17 at 22:42