templates, arrays and size

N

Nick Valeontis

I am confused.

Why does this not work?

---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
template<class T> void PrintArray(T data[], int start, int stop, int
col_length = 3) {
for (int i = start; i <= stop; i++)
std::cout << std::setw(col_length) << data << " ";
std::cout << std::endl;
}

template<class T> void PrintArray(T data[], int col_length = 3) {
//sizeof(data)/sizeof(typeof(data[0]) = 0 !:O
PrintArray(data, 0, sizeof(data)/sizeof(typeof(data[0])), col_length);
}
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
---- ----

If i run the same expression in my main, i get the correct result.. :( ????
 
R

Robert Bauck Hamar

Nick said:
I am confused.

Why does this not work?

Because an array in an argument list really is a pointer. Try:

void foo(int data[]) {
std::cout << sizeof(data)/sizeof(data[0]);
}
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
template<class T> void PrintArray(T data[], int start, int stop, int
col_length = 3) {
for (int i = start; i <= stop; i++)
std::cout << std::setw(col_length) << data << " ";
std::cout << std::endl;
}

template<class T> void PrintArray(T data[], int col_length = 3) {
//sizeof(data)/sizeof(typeof(data[0]) = 0 !:O
PrintArray(data, 0, sizeof(data)/sizeof(typeof(data[0])), col_length);
}


try:
template <class T, std::size_t N>
void PrintArray(T data[N], int col_length = 3) {
PrintArray(data, 0, N, col_length);
}
---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----

Yes. As you can see, sizeof is a compile time operator, that is the result
is known at compile time. If your function had worked, this would have
required one instance of PrintArray(T[],int) for each size of the array.

btw, typeof isn't part of standard C++.
 
I

Ivan Vecerina

:I am confused.
:
: Why does this not work?
:
: ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
----
: template<class T> void PrintArray(T data[], int start, int stop, int
: col_length = 3) {
: for (int i = start; i <= stop; i++)
: std::cout << std::setw(col_length) << data << " ";
: std::cout << std::endl;
: }
:
: template<class T> void PrintArray(T data[], int col_length = 3) {
In this context, T data[] declares a parameter of
type pointer-to-T.

: //sizeof(data)/sizeof(typeof(data[0]) = 0 !:O
: PrintArray(data, 0, sizeof(data)/sizeof(typeof(data[0])),
col_length);
: }

What you want to do instead is declare the parameter
as a reference to an array:
template<class T, unsigned N> inline
void PrintArray(T (&data)[N], int col_length = 3)
{ PrintArray(data,0,N,col_length); }

This should do what you expected...
 
N

Nick Valeontis

K, thanks both.

I think i have understood why this is happening.

Now, i tested your suggestions. This works okay and does what I want indeed:

template<class T, unsigned N> void PrintArray(T (&data)[N], int col_length =
3);


However, this does not work:

template<class T, unsigned N> void PrintArray(T data[N], int col_length =
3);

I get "no matching function for call to `PrintArray(int[10])' " error when i
try something like this:

--- --- --- --- --- ---
int data[] = { 9,7,5,8,2,6,4,3,1,0 };
PrintArray(data);
--- --- --- --- --- ---

Why is that? :/
 
R

Robert Bauck Hamar

Nick said:
K, thanks both.

I think i have understood why this is happening.

Now, i tested your suggestions. This works okay and does what I want
indeed:

template<class T, unsigned N> void PrintArray(T (&data)[N], int col_length
= 3);


However, this does not work:

template<class T, unsigned N> void PrintArray(T data[N], int col_length =
3);

I get "no matching function for call to `PrintArray(int[10])' " error when
i try something like this:

--- --- --- --- --- ---
int data[] = { 9,7,5,8,2,6,4,3,1,0 };
PrintArray(data);
--- --- --- --- --- ---

Why is that? :/

I was a little too sloppy while posting. The leftmost array dimension is not
really part of the type when the array is a parameter, because an array is
a pointer to its first element when it is a function parameter. There's
even a note in the standard specifying that the second example shouldn't
work. Making data a reference changes this.
 
N

Nick Valeontis

ok,

I think I see what you mean.

In "T data[N]", N is not part of the type, so essentially "T data[]" simply
means "T* data". data is pointer to the first T of many Ts placed one after
the other in memory.

And saying that data is a pointer to N Ts ("T data[N]") is not meaningful.
data's type is a pointer to a single T. Right?

But, in "T (&data)[N]", data is a reference to something, and a reference to
N Ts and a reference to M Ts are of a different type.

So saying that data is a reference to the first T of many Ts is not enough.
You have to define the number of the Ts that exist in order to define the
reference.

Does what i am writing makes sense?


Thank you for your time!

Nick


Robert Bauck Hamar said:
Nick said:
K, thanks both.

I think i have understood why this is happening.

Now, i tested your suggestions. This works okay and does what I want
indeed:

template<class T, unsigned N> void PrintArray(T (&data)[N], int
col_length
= 3);


However, this does not work:

template<class T, unsigned N> void PrintArray(T data[N], int col_length =
3);

I get "no matching function for call to `PrintArray(int[10])' " error
when
i try something like this:

--- --- --- --- --- ---
int data[] = { 9,7,5,8,2,6,4,3,1,0 };
PrintArray(data);
--- --- --- --- --- ---

Why is that? :/

I was a little too sloppy while posting. The leftmost array dimension is
not
really part of the type when the array is a parameter, because an array is
a pointer to its first element when it is a function parameter. There's
even a note in the standard specifying that the second example shouldn't
work. Making data a reference changes this.
 
R

Robert Bauck Hamar

Nick said:
ok,

I think I see what you mean.

In "T data[N]", N is not part of the type, so essentially "T data[]"
simply means "T* data". data is pointer to the first T of many Ts placed
one after the other in memory.

Yes. 'T data[]', 'T data[N]' (for some constant integral expression N)
and 'T *data' in a function parameter list, means exactly the same: A
pointer. This is to C++, though. A person seeing T data[] would probably
read that the function expects an array. But then again: This should be
documented anyway.
And saying that data is a pointer to N Ts ("T data[N]") is not meaningful.
data's type is a pointer to a single T. Right?

C++ throws away the N. It's the programmer's responsibility to keep track of
it.
But, in "T (&data)[N]", data is a reference to something, and a reference
to N Ts and a reference to M Ts are of a different type.

Yes. Reference and pointer types has the dimensions as part of the type. If
you are passing a multidimensional array, all but the first dimensions can
be deduced:

T data[][N]
T (*data)[N]

has the same meaning, and can deduce both T and N as template parameters.
So saying that data is a reference to the first T of many Ts is not
enough.

We aren't. 'T (&data)[N]' declares data as a reference to an array of N Ts.
You have to define the number of the Ts that exist in order to
define the reference.

A reference type holds all of the information of the referenced type. Since
the referenced type is an array, the dimensions must be known.

Note that T (&data)[N] can only bind to a real array, you cannot use
pointers to dynamically allocated arrays, for instance.


[snip quote discussing template <class T, int N> void foo(T data[N]) vs
foo(T (&data)[N])]
 
B

Bo Persson

Nick Valeontis wrote:
:: ok,
::
:: I think I see what you mean.
::
:: In "T data[N]", N is not part of the type, so essentially "T
:: data[]" simply means "T* data". data is pointer to the first T of
:: many Ts placed one after the other in memory.
::
:: And saying that data is a pointer to N Ts ("T data[N]") is not
:: meaningful. data's type is a pointer to a single T. Right?
::
:: But, in "T (&data)[N]", data is a reference to something, and a
:: reference to N Ts and a reference to M Ts are of a different type.
::
:: So saying that data is a reference to the first T of many Ts is
:: not enough. You have to define the number of the Ts that exist in
:: order to define the reference.
::
:: Does what i am writing makes sense?
::

Yes.

This all comes down to a limitation of the C language, where you
cannot pass an array as a parameter. You have to pass a pointer.

In C++ this means that you can pass a pointer to an array, a reference
to an array, or a class containing an array, like std::vector (hint,
hint! :).


Not using arrays, unless you absolutely have to, saves you a lot of
trouble!


Bo Persson
 
N

Nick Valeontis

ok,

I 'd like to thank you all who answered!

You have been very informative ;-)



-Nick
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,196
Latest member
ScottChare

Latest Threads

Top