David258
David258

Reputation: 757

C++ Templates ByRef vs. ByVal

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&) ?

Upvotes: 1

Views: 1077

Answers (1)

Ben Voigt
Ben Voigt

Reputation: 283961

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.

Upvotes: 3

Related Questions