Overload template function in a class?

Pages: 12
@CroCo
@AdrianH,
Interesting but what is the difference between
void save_Data_inFile(const double (&data)[3])
and
void save_Data_inFile(const double data[3])

As far as I know, the name of an array is a const pointer. What is the effect of & with first prototype?

I think what you mean is that the type of an array is a const pointer. That is incorrect. The type of an array is an array, but an array can decay into a pointer.

Your 1st example takes an array that has 3 elements, the 2nd example takes a pointer.

Given my previous code and the following example. you can see how the type system is keeping you from passing a type that is not expected, which can potentially avoid runtime errors.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include "FILE_txt.h"

int main()
{
        FILE_txt myfile("fullpath");
	double (&array1)[3] = *new double[1][3] {2,3,4};
        double   array2 [3] = {2,3,4};
	double (&array3)[4] = *new double[1][4] {2,3,4};
        double   array4 [4] = {2,3,4};
	double (&array5)[2] = *new double[1][2] {2,3};
        double   array6 [2] = {2,3};
	
        // The following lines call function
        //   template<class T>
        //   void FILE_txt::save_Data_inFile(const T (&data)[3])
        // or
        //   template<class T, size_t N>
        //   typename std::enable_if<(N>=3)>::type FILE_txt::save_Data_inFile(const T (&data)[N])
        // If both signatures were available, this would cause an 
        // ambiguity error since both would match.
	myfile.save_Data_inFile(array1);
	myfile.save_Data_inFile(array2);

        // The following lines call function
        //   template<class T, size_t N>
        //   typename std::enable_if<(N>=3)>::type FILE_txt::save_Data_inFile(const T (&data)[N])
	myfile.save_Data_inFile(array3);
	myfile.save_Data_inFile(array4);

        // The following fails to compile due to type mismatch:
	myfile.save_Data_inFile(array5);
	myfile.save_Data_inFile(array6);

        // The following would fail as there's no function that takes a pointer even
        // though numbers is a pointer to a type that would have been valid.
        // If your 2nd function signature example was available, it would be called
        // which would be incorrect for the 1st call using number as a parameter.
        double *number  = new number(3);
        double *numbers = array2;
        myfile.save_Data_inFile(number);
	myfile.save_Data_inFile(numbers);

        delete number; // delete number
        delete[] &array1; // delete elements in array1
        delete[] &array3; // delete elements in array3
        delete[] &array5; // delete elements in array5
        
	std::cin.get();

	return 0;
}

EDIT: Actually since array1, 3 and 5 will decay to a pointer, you could delete them like this instead:
1
2
3
        delete[] array1; // delete elements in array1
        delete[] array3; // delete elements in array3
        delete[] array5; // delete elements in array5 
Last edited on
@Zhuge,

The second behaves as you expect, but the first says take a reference to something of type double[3] and call it data.

First prototype:
void save_Data_inFile(const double (&data)[3])

I still don't see any benefit of using the first prototype. You're saying it takes a reference, I'm aware of passing by reference; however, with an array, we're actually passing by reference, so it seems to me there is no benefit of doing so. I know it works but I haven't encountered this syntax in many c++ books that I've read so far.

@AdrianH ,

I think what you mean is that the type of an array is a const pointer. That is incorrect. The type of an array is an array, but an array can decay into a pointer.

No, I mean the name of an array. For example,
double array[3] = {1, 2, 3};
Now if I use
std::cout << array << std::endl;
I'm expecting an address. Moreover, if I dereference it, I will get the value of the first element. What I've noticed is that there is no difference between array and (&array). Both are holding same address.

The type of an array is an array, but an array can decay into a pointer.

I don't know if I understood what you meant by saying The type of an array is an array. With the following
double array[3] = {1, 2, 3};
the type of the array is double because it holds double values.
Last edited on
First prototype:
void save_Data_inFile(const double (&data)[3])

I still don't see any benefit of using the first prototype. You're saying it takes a reference, I'm aware of passing by reference; however, with an array, we're actually passing by reference, so it seems to me there is no benefit of doing so.

Arrays are passed (by default) by pointer to the first element. This is not passing by reference. This is passing a pointer by value. The difference between passing a pointer and a reference to an array is that the full type information is preserved with a reference and the type is more restrictive.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <typeinfo>

// func_a takes a pointer to int 
// the 5 in the parameter type is ignored.
void func_a( int myarray[5] )
{
    std::cout << "func_a\n\ttype: " ;
    std::cout << typeid(myarray).name() << "\n\tsize: " ;
    std::cout << sizeof(myarray) << "\n\n" ;

    // ++myarray ; would be legal here.
    // myarray = 0 ; would be legal here.
}

// func_b takes a reference to int[5]; 
// the 5 in the parameter type is not ignored.
void func_b( int(&myarray)[5] )
{
    std::cout << "func_b\n\ttype: " ;
    std::cout << typeid(myarray).name() << "\n\tsize: " ;
    std::cout << sizeof(myarray) << "\n\n" ;

    // ++myarray; would be illegal here.
    // myarray=0; would be illegal here.
}

int main()
{
    int a1[5] ;
    int a2[2] ;

    func_a(a1) ;    // legal
    func_a(a2) ;    // legal

    func_b(a1) ;    // legal
//  func_b(a2) ;    // illegal
}
func_a
        type: int *
        size: 4

func_a
        type: int *
        size: 4

func_b
        type: int [5]
        size: 20



What I've noticed is that there is no difference between array and (&array). Both are holding same address.

There is a difference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <typeinfo>

int main()
{
    double array[3] ;
    std::cout << typeid(array).name() << '\n' ;
    std::cout << sizeof(array) << "\n\n" ;

    std::cout << typeid(&array).name() << '\n' ;
    std::cout << sizeof(&array) << "\n\n" ;

    std::cout << typeid(*array).name() << '\n' ;
    std::cout << sizeof(*array) << "\n\n" ;

    std::cout << typeid(*(&array)).name() << '\n' ;
    std::cout << sizeof(*(&array)) << "\n\n" ;

    std::cout << array+1 << '\n' ;
    std::cout << &array + 1 << "\n\n" ;
}
double [3]
24

double (*)[3]
4

double
8

double [3]
24

03D0FD54
03D0FD64



With the following
double array[3] = {1, 2, 3};
the type of the array is double because it holds double values.

The type of the array is double[3] because it is an array of 3 doubles.
Last edited on
@cire,
Thank you so much. I got it now. It is really peculiar that many books don't mention the difference between passing an array by reference and a pointer.
Topic archived. No new replies allowed.
Pages: 12