2

I have this example from C++ 5th ed.:

template <typename T> T fobj(T, T); // arguments are copied
template <typename T> T fref(const T&, const T&); // references
string s1("a value");
const string s2("another value");
fobj(s1, s2); // calls fobj(string, string); const is ignored
fref(s1, s2); // calls fref(const string&, const string&)
              // uses premissible conversion to const on s1
int a[10], b[42];
fobj(a, b); // calls f(int*, int*)
fref(a, b); // error: array types don't match

"In the next pair of calls, we pass array arguments in which the arrays are different sizes and hence have different types. In the call to fobj, the fact that the array types differ doesn’t matter. Both arrays are converted to pointers. The template parameter type in fobj is int*. The call to fref, however, is illegal. When the parameter is a reference, the arrays are not converted to pointers (§ 6.2.4, p. 217). The types of a and b don’t match, so the call is in error."

  • I have only a confusion about the last call fref(a, b): Why it is illegal?

  • I think because the size of an array is a part of its type it is OK until here so a has the type int[10] while b has the type int[42] But the problem is whatever I try to make the size the same it fails to compile:

      int a[10], b[10];
      fref(a, b); // error: array types don't match
    
       int a[10], b[42];
       fref(a, a); // error: array types don't match
    

As you can see I've made a and b of the same type nevertheless it still fails to compile and even if I pass the same array a or b twice to fref it fails.

So why I still get error: array types don't match? thank you.

  • I think it is mistake in the book "The types of a and b don’t match, so the call is in error". And there's another problem because I've made the arrays of the same type and still don't work.
Maestro
  • 2,512
  • 9
  • 24
  • 1
    First note that [arrays are not pointers](https://stackoverflow.com/questions/28790204/pointer-to-arrays-syntax/28790232#28790232), but they **can** decay to pointers. That is what happens in the `fobj` call. But in the `fref` call they do not decay into pointers and, since the array size is **part of the type**, you have different types and thus a compiler error. – darcamo Nov 17 '20 at 21:06
  • @darcamo: But I don't think so. Because I've made the second example of the same type `a` and `b` are arrays to `10` integers. Please re-read it. Thank you – Maestro Nov 17 '20 at 21:07
  • 2
    @darcamo that was my first thought too, but if you check the end of the question they try to circumvent that problem without success. – Mark Ransom Nov 17 '20 at 21:08
  • I've edited the topic because I've already copied the wrong paragraph. – Maestro Nov 17 '20 at 21:16
  • 1
    The type of an array (or reference to an array) depends on the number of elements it has. So an array with 10 elements differs in type from an array of 42 elements. When the two arrays passed are the same size, the problem is that returning an array by value is not possible - to fix that either change the return type to be a reference (which means whatever is returned must exist after the function returns, and other constraints - and if returning one of the arguments, the returned reference must also be `const`) or to return something else. – Peter Nov 17 '20 at 21:31

2 Answers2

6

For this function template:

template <typename T> 
T fref(const T&, const T&); 

when you make the call:

int a[42];
fref(a, a);

template argument deduction will deduce T to be int[42]. The call fails to compile, but the reason in your question, i.e. // error: array types don't match is incorrect, because the array types do indeed match.

The reason the call fails to compile is because the return type is also T, and you cannot return array types, such as int[42] from a function.

You can fix this in any way such that fref has a valid return type, e.g. you could return void:

template <typename T> void fref(const T&, const T&); 
cigien
  • 57,834
  • 11
  • 73
  • 112
  • Great and amazing! many thanks. It never crossed my mind. Yes sure we cannot return an array. – Maestro Nov 17 '20 at 21:17
  • I do really appreciate it. I've corrected another way: made `fref` return a reference or a pointer to `T` also works: `template T& fref(...)`. – Maestro Nov 17 '20 at 21:19
  • I changed the return type to void just before you posted your answer and reached the same reason. I would even call this a "bug" in the compiler since the types match and the compiler is telling us *wrong information*. – darcamo Nov 17 '20 at 21:19
  • @Maestro No problem :) Yeah, I wasn't sure what you actually wanted to return, since the question seemed theoretical. `T&` is reasonable, but as usual, be careful about dangling references. – cigien Nov 17 '20 at 21:20
  • @darcamo: It works fine it is really so logical because we cannot return an array or function directly. – Maestro Nov 17 '20 at 21:20
  • Yes you are correct. So That is a mistake in the book (b and a are of different types thus it fails)? I think it is correct only if the return type is valid and the arrays are of different sizes thus different types. What do you think? – Maestro Nov 17 '20 at 21:21
  • 1
    @Maestro I didn't actually read the text before :p but yeah, that comment `//error: array types don't match` is wrong. – cigien Nov 17 '20 at 21:24
  • @Maestro I edited the answer to point out the text book is wrong. I thought you were misreading a diagnostic before. – cigien Nov 17 '20 at 21:26
  • In fact in the book example the types don't really match thus even if we make the return of `fref` a reference or a pointer or void it still fails to compile because in the book `a` is `int[10]` while `b` is `int[42]` thus these cause an the same error. But my example I made them of the same type. – Maestro Nov 17 '20 at 21:28
  • @Maestro Oh, so *you* left the comment in after changing the type of `a` and `b` to match? If so, I'll edit the answer again. – cigien Nov 17 '20 at 21:29
  • Yes that is it exactly. – Maestro Nov 17 '20 at 21:30
  • Ok. Thank you again! – Maestro Nov 17 '20 at 21:33
0

Your example with the same array sizes would work, if you would change the function template

from:

template <typename T> T fref(const T&, const T&); // references

to:

template <typename T> const T& fref(const T&, const T&); // references

It depends on what you intent to return.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11