473,545 Members | 1,989 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Typed arrays (was: Is it ANSI or is it compiler dependent?)

"Leor Zolman" <le**@bdsoft.co m> wrote
"Canonical Latin" <ja******@hotma il.com> wrote:
...
But I'm still curious as to the rational of having type
pointer-to-array-of-size-N-of-type-T (which is fine) and not having type
array-of-size-N-of-type-T (with some exceptions, which is curious).
So far
the consensus seems to be that while everyone is aware of this no one knowsthe rational behind it. I'm sure there must be a compelling reason for thisand once explained it would be obvious :)

I know you asked me not to answer any more of your questions, but I'm
stubborn ;-)

The place where you can't have array-of-size-N is in the special case of a
function parameter. Otherwise they're fine.

In the case of function parameters, if an array got passed by value, that
would be a very expensive operation. Most of the time folks would have to
program around it, by writing an expression that evaluates to a pointer of
some kind and passing /that/. But believe it or not, if arrays got passed
by value, that would actually be the special case...because of the
following:

As I'm fond of saying, arrays are just "smoke and mirrors" anyway; they're
mostly syntactic sugar, and compilers translate array names into pointers
to their first elements (there are a few exceptions, such as when applying
sizeof). That's true even if you don't pass them to a function.

So, given:
int a[10];
a[3] = 5;

that last line actually compiles into something like:
*(&a[0] + 3) = 5;

Therefore, in a function call such as:
func(a);

it makes perfect sense what gets passed is a pointer to the first element
of the array:

func(&a[0]);

and thus there's no information available to the function about the size

of that array.
-leor

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html


Type checking and passing by value are two different issues. Consider:

fun1 (T[]); // pointer-to-type-T

fun2 (T[2]); // array-of-size-2-of-type-T

fun3 (T[3]); // array-of-size-3-of-type-T

fun4 (T**); // pointer-to-pointer-to-type-T

fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T

fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T

In none of the cases the whole array is passed by value and this is not the
issue. Suppose that c++ actually did have a legitimate type
array-of-size-N-of-type-T. Then

fun (T x[]); // fun1

fun (T x[2]); // fun2

fun (T x[3]); // fun3

main() {

T a[2];

T b[3];

T c[4];

T *d;

fun(a); // call fun2

fun(b) ; // call fun3

fun(c) ; // call fun1 (see comment at end)

fun(d) ; // call fun1

}

Obviously this doesn't work in c++ because compiler sees
array-of-size-N-of-type-T as pointer-to-type-T in most cases. Enforcing type
checking for arrays has nothing to do with passing the whole array by value.
If you think my description of supposed behavior is too far fetched, or that
arrays are just "smoke and mirror" then consider

void fun (T **x) { cout << "fun1"; }

void fun (T (*x)[2]) { cout << "fun2"; }

void fun (T (*x)[3]) { cout << "fun3"; }

int main(int argc, char *argv[]) {

T (*a)[2];

T (*b)[3];

T (*c)[4];

T **d;

fun(a); // call fun2

fun(b) ; // call fun3

fun((T**)(c)) ; // call fun1 (unsafe in c++)

fun(d) ; // call fun1

}

which compiles and behaves as expected. Note that nothing is passed by
value. What this is saying is that pointer-to-array-of-size-N-of-type-T is a
different type for each value of N. What I am saying is that so far I have
not heard a compelling reason why array-of-size-N-of-type-T should not also
be a different type for each value of N.

Another issue that is closely related to this: There is already a problem in
c++ with type pointer-to-array-of-size-N-of-type-T which I marked as
"unsafe" in my example. Essentially you cannot convert
pointer-to-array-of-size-N-of-type-T to pointer-to-pointer-of-type-T without
using a reinterpret cast. This perhaps is the source of the odd behavior of
reinterpreting array-of-size-N-of-type-T as pointer-to-type-T. Of course,
this whole business would go away (and we get true typed arrays in bargain)
if array-of-size-N-of-type-T is automatically converted to pointer-to-type-T
only if there is no matching type for the specific value of N.
Jul 22 '05 #1
19 2827


"Andrey Tarasevich" <an************ **@hotmail.com> wrote in message
news:10******** *****@news.supe rnews.com...
Leor Zolman wrote:
In the case of function parameters, if an array got passed by value, that would be a very expensive operation. Most of the time folks would have to program around it, by writing an expression that evaluates to a pointer of some kind and passing /that/. But believe it or not, if arrays got passed by value, that would actually be the special case...


That's not really true. Conceptually, arrays are aggregates and in this
respect they are not different from structs. Making arrays passable "by
value" wouldn't make things more complicated or inconvenient they
already are with structs. Folks would have to do the same thing they
always did - if you want to pass something large and don't need a copy -
pass it "by pointer".

Actually, impossibility to pass arrays by value made things _more_
cumbersome and error prone, because it breaks the invariance of the code
with respect to aggregate types hidden behind typedef-names. The
following function will accepts its parameters very differently,
depending on whether typedef-name 'T' designates array type or struct type

void foo(T agg)

and that's not a good thing.
because of the following:

As I'm fond of saying, arrays are just "smoke and mirrors" anyway; they're mostly syntactic sugar, and compilers translate array names into pointers to their first elements (there are a few exceptions, such as when applying sizeof).


The only reason you can call these contexts (where arrays don't decay
into pointers) "exceptions " is that these contexts are apparently
relatively rare compared to the contexts where arrays do decay to
pointers (especially true for C). But that's a fake reason. Nothing more
than an illusion.

From the formal point of view, arrays keeping their "arrayness" is the
_normal_ behavior of arrays, while arrays decaying into pointers is the
abnormal (exceptional) behavior. It is definitely not correct to say
that arrays are just "smoke and mirrors".
That's true even if you don't pass them to a function.

So, given:
int a[10];
a[3] = 5;

that last line actually compiles into something like:
*(&a[0] + 3) = 5;

Therefore, in a function call such as:
func(a);

it makes perfect sense what gets passed is a pointer to the first element of the array:

func(&a[0]);

and thus there's no information available to the function about the size of that array.


Well, it is also important to understand that allowing an array to decay
to a pointer when passed to a function is a useful trick, which has its
own specific purpose. It purpose is to help create functions that can
work with arrays of different sizes.

In contexts where the ability to work with differently sized arrays is
not needed, it makes more sense to pass arrays by array-typed
pointer/reference (i.e. by a pointer/reference of
pointer/reference-to-array type). For example, an application that works
with, say, 3d geometry and used the following type to represent points
in 3D space

typedef int point_t[3];

should pass these points to functions as follows

void foo(const point_t& point)

or

void bar(const int (&point)[3])

not as

void foo(const point_t point)
void bar(const int point[3])

Note, that such function declaration are invariant to the possible
future change of 'point_t' definition to

typedef struct point_t { int x, y, z; };

--
Best regards,
Andrey Tarasevich


I like your reply Andery. But your idea is a bit more revolutionary than
mine. Read my alternative solution of decaying array-to-size-N-of-type-T to
pointer-to-type-T only if there is no matching type for N in the new thread
"Typed Arrays". I won't shy away from some constructive criticism :)

Jul 22 '05 #2
Canonical Latin wrote:
...
Type checking and passing by value are two different issues. Consider:

fun1 (T[]); // pointer-to-type-T

fun2 (T[2]); // array-of-size-2-of-type-T

fun3 (T[3]); // array-of-size-3-of-type-T

fun4 (T**); // pointer-to-pointer-to-type-T

fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T
No, it is an array of 2 'T*'s.
fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T
No, it is an array of 3 'T*'s.

You probably meant

fun5(T(*)[2])
fun5(T(*)[3])

In none of the cases the whole array is passed by value and this is not the
issue. Suppose that c++ actually did have a legitimate type
array-of-size-N-of-type-T. Then
But, C++ does have a legitimate type array-of-size-N-of-type-T. Not
fully functional though.
fun (T x[]); // fun1

fun (T x[2]); // fun2

fun (T x[3]); // fun3

main() {

T a[2];

T b[3];

T c[4];

T *d;

fun(a); // call fun2

fun(b) ; // call fun3

fun(c) ; // call fun1 (see comment at end)

fun(d) ; // call fun1

}

Obviously this doesn't work in c++ because compiler sees
array-of-size-N-of-type-T as pointer-to-type-T in most cases.
It is not exactly correct. Compiler sees array-of-size-N-of-type-T as
pointer-to-type-T in case of function parameter declaration. The rest
follows. This is specific to situations when one makes syntactical
attempt to pass arrays "by value".

Note, that if you declare your functions as

fun (T (&x)[2]); // fun2
fun (T (&x)[3]); // fun3

the overloading will start working as you describe.
Enforcing type
checking for arrays has nothing to do with passing the whole array by value.
If you think my description of supposed behavior is too far fetched, or that
arrays are just "smoke and mirror" then consider

void fun (T **x) { cout << "fun1"; }

void fun (T (*x)[2]) { cout << "fun2"; }

void fun (T (*x)[3]) { cout << "fun3"; }

int main(int argc, char *argv[]) {

T (*a)[2];

T (*b)[3];

T (*c)[4];

T **d;

fun(a); // call fun2

fun(b) ; // call fun3

fun((T**)(c)) ; // call fun1 (unsafe in c++)

fun(d) ; // call fun1

}

which compiles and behaves as expected. Note that nothing is passed by
value. What this is saying is that pointer-to-array-of-size-N-of-type-T is a
different type for each value of N. What I am saying is that so far I have
not heard a compelling reason why array-of-size-N-of-type-T should not also
be a different type for each value of N.
It _is_ a different type for each value of on. In certain contexts this
difference is lost because of array-to-pointer conversion.
Another issue that is closely related to this: There is already a problem in
c++ with type pointer-to-array-of-size-N-of-type-T which I marked as
"unsafe" in my example. Essentially you cannot convert
pointer-to-array-of-size-N-of-type-T to pointer-to-pointer-of-type-T without
using a reinterpret cast. This perhaps is the source of the odd behavior of
reinterpreting array-of-size-N-of-type-T as pointer-to-type-T. Of course,
this whole business would go away (and we get true typed arrays in bargain)
if array-of-size-N-of-type-T is automatically converted to pointer-to-type-T
only if there is no matching type for the specific value of N.


Hmm.. I don't exactly understand what you are trying to say here.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #3

"Andrey Tarasevich" <an************ **@hotmail.com> wrote in message
news:10******** *****@news.supe rnews.com...
Canonical Latin wrote:
...
Type checking and passing by value are two different issues. Consider:

fun1 (T[]); // pointer-to-type-T
fun2 (T[2]); // array-of-size-2-of-type-T
fun3 (T[3]); // array-of-size-3-of-type-T
fun4 (T**); // pointer-to-pointer-to-type-T
fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T
No, it is an array of 2 'T*'s.
fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T


No, it is an array of 3 'T*'s.

You probably meant

fun5(T(*)[2])
fun5(T(*)[3])


Oops! Yes I did mean that

In none of the cases the whole array is passed by value and this is not the issue. Suppose that c++ actually did have a legitimate type
array-of-size-N-of-type-T. Then


But, C++ does have a legitimate type array-of-size-N-of-type-T. Not
fully functional though.
fun (T x[]); // fun1
fun (T x[2]); // fun2
fun (T x[3]); // fun3
main() {
T a[2];
T b[3];
T c[4];

T *d;
fun(a); // call fun2
fun(b) ; // call fun3
fun(c) ; // call fun1 (see comment at end)
fun(d) ; // call fun1
}

Obviously this doesn't work in c++ because compiler sees
array-of-size-N-of-type-T as pointer-to-type-T in most cases.


It is not exactly correct. Compiler sees array-of-size-N-of-type-T as
pointer-to-type-T in case of function parameter declaration. The rest
follows. This is specific to situations when one makes syntactical
attempt to pass arrays "by value".

Note, that if you declare your functions as

fun (T (&x)[2]); // fun2
fun (T (&x)[3]); // fun3

That is great. It is almost there. The only problem is that now you cannot
have
fun (T x[]); // fun1
and call it with
T xx[4];
fun(xx);
the overloading will start working as you describe.
Enforcing type
checking for arrays has nothing to do with passing the whole array by value. If you think my description of supposed behavior is too far fetched, or that arrays are just "smoke and mirror" then consider

void fun (T **x) { cout << "fun1"; }
void fun (T (*x)[2]) { cout << "fun2"; }
void fun (T (*x)[3]) { cout << "fun3"; }
int main(int argc, char *argv[]) {
T (*a)[2];
T (*b)[3];
T (*c)[4];
T **d;
fun(a); // call fun2
fun(b) ; // call fun3
fun((T**)(c)) ; // call fun1 (unsafe in c++)
fun(d) ; // call fun1
}

which compiles and behaves as expected. Note that nothing is passed by
value. What this is saying is that pointer-to-array-of-size-N-of-type-T is a different type for each value of N. What I am saying is that so far I have not heard a compelling reason why array-of-size-N-of-type-T should not also be a different type for each value of N.
It _is_ a different type for each value of on. In certain contexts this
difference is lost because of array-to-pointer conversion.
Another issue that is closely related to this: There is already a problem in c++ with type pointer-to-array-of-size-N-of-type-T which I marked as
"unsafe" in my example. Essentially you cannot convert
pointer-to-array-of-size-N-of-type-T to pointer-to-pointer-of-type-T without using a reinterpret cast. This perhaps is the source of the odd behavior of reinterpreting array-of-size-N-of-type-T as pointer-to-type-T. Of course, this whole business would go away (and we get true typed arrays in bargain) if array-of-size-N-of-type-T is automatically converted to pointer-to-type-T only if there is no matching type for the specific value of N.


Hmm.. I don't exactly understand what you are trying to say here.

I'm not sure I do either, but I try! Here is another attempt: as it is,
array-of-size-N-of-type-T decays to pointer-of-type-T when not argument to
sizeof and as you noted not qualified by &. Lets say I want array type
checking and still want to be able to pass T[N] to a function that does not
specify the N value e.g.
fun(T *x); // funA
fun(T (&x)[2]); // funB
main() {
T x[3] ;
fun(x) ; // funA
}
So the compiler tries to find fun(T (&x)[3]) and since it can't then it
automatically looks for fun(T *x); // funA

--
Best regards,
Andrey Tarasevich


Jul 22 '05 #4
On Tue, 11 May 2004 22:01:40 GMT, "Canonical Latin" <ja******@hotma il.com>
wrote:

Type checking and passing by value are two different issues. Consider:

fun1 (T[]); // pointer-to-type-T
yes.

fun2 (T[2]); // array-of-size-2-of-type-T
Now, are you showing what you'd like it to be, or what you think is
actually being declared? As per all that's been said before, the type of
the parameter above is actually the same as the previous: pointer-to-T.

fun3 (T[3]); // array-of-size-3-of-type-T
again, just pointer-to-T.

fun4 (T**); // pointer-to-pointer-to-type-T
yes.

fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T
Nope, just pointer-to-pointer-to-T.

fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T
Still just pointer-to-pointer-to-T.

In none of the cases the whole array is passed by value and this is not the
issue. Suppose that c++ actually did have a legitimate type
array-of-size-N-of-type-T. Then

fun (T x[]); // fun1

fun (T x[2]); // fun2

fun (T x[3]); // fun3

main() {

T a[2];

T b[3];

T c[4];

T *d;

fun(a); // call fun2

fun(b) ; // call fun3

fun(c) ; // call fun1 (see comment at end)

fun(d) ; // call fun1
/IF/ C++ did as you'd like, then it would break all pre-existing code that
relies on the age-old behavior of arrays "decaying" to pointers. Imagine
requiring there to be an overload for each possible length N in cases such
as:

char string[N];
...
int i = strlen(string);

Would we want to have to have a separately compiled version of strlen for
each possible value of N? Or for strlen to be a template with a non-type
template parameter N? Yuck.

}

Obviously this doesn't work in c++ because compiler sees
array-of-size-N-of-type-T as pointer-to-type-T in most cases.
Remember that arrays retain their full type information as long as the
name they were declared with (as arrays) is still in scope and you use it.
That's why sizeof(array) works and &array actually yields a
pointer-to-array. But most of the things you do with arrays, such as
subscripting, end up with you losing that "array-ness" because it is no
longer needed by the resulting expression type. The fact this information
is also lost when using an array as a function argument is just an
occupational hazard of C/C++ programming. Check out today's thread with
subject "Copying struct with array" for some history as to why structure
assignment is allowed while array assignment is not; it's quite related to
this issue.
Enforcing type
checking for arrays has nothing to do with passing the whole array by value.
If you think my description of supposed behavior is too far fetched, or that
arrays are just "smoke and mirror" then consider
It's not that I just /think/ they're smoke and mirrors, I know from having
implemented a C compiler by hand that native C/C++ arrays are essentially
nothing more than notational convenience (and extremely so in the case of
array function parameters). If you want object semantics for something
that works like an array, simply use a vector, or even boost::array if you
don't require dynamic resizing.

Every so often folks suggest how things "should" be in C or C++, and it
isn't that they aren't good ideas, but they're not good enough for the
chaos attempting to retro-fit them to the language /now/ would inevitably
cause. C++ is difficult enough to grok as it stands. I think the entire C++
community is only barely beginning to feel a bit of relief that compilers
in general have /almost/ caught up with the language as it was standardized
in 1998 (and only one family, the one based on the EDG front end, actually
has). Changes to the basic semantics of arrays just aren't going to happen.

void fun (T **x) { cout << "fun1"; }

void fun (T (*x)[2]) { cout << "fun2"; }

void fun (T (*x)[3]) { cout << "fun3"; }

int main(int argc, char *argv[]) {

T (*a)[2];

T (*b)[3];

T (*c)[4];

T **d;

fun(a); // call fun2

fun(b) ; // call fun3

fun((T**)(c)) ; // call fun1 (unsafe in c++)

fun(d) ; // call fun1

}

which compiles and behaves as expected. Note that nothing is passed by
value. What this is saying is that pointer-to-array-of-size-N-of-type-T is a
different type for each value of N. What I am saying is that so far I have
not heard a compelling reason why array-of-size-N-of-type-T should not also
be a different type for each value of N.
As I said above, even if this would be an overall improvement to the
language (and I'm not saying it would be; I haven't completely thought it
through, and I'm not likely to), it would no longer be C or C++ and thus
could not possibly be worth breaking most of the existing C/C++ code base
to effect.

Note that using boost::array, you can achieve the overloading you want,
retain full performance of native arrays, and still "pass" arrays as
efficiently as C/C++ doesn't (just pass by reference).

Another issue that is closely related to this: There is already a problem in
c++ with type pointer-to-array-of-size-N-of-type-T which I marked as
"unsafe" in my example. Essentially you cannot convert
pointer-to-array-of-size-N-of-type-T to pointer-to-pointer-of-type-T without
using a reinterpret cast. This perhaps is the source of the odd behavior of
reinterpreti ng array-of-size-N-of-type-T as pointer-to-type-T. Of course,
this whole business would go away (and we get true typed arrays in bargain)
if array-of-size-N-of-type-T is automatically converted to pointer-to-type-T
only if there is no matching type for the specific value of N.
Passing multi-dimensional arrays around takes some intestinal fortitude. It
always confuses the hell out of /me/, so I can't disagree about the
languages being weak in that regard. To make matters worse, there are no
wonderful replacements for multidimensiona l arrays in the modern C++ libs,
alas (at least none I've found yet.)
-leor


--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Jul 22 '05 #5
"Leor Zolman" <le**@bdsoft.co m> wrote in message
news:om******** *************** *********@4ax.c om...
On Tue, 11 May 2004 22:01:40 GMT, "Canonical Latin" <ja******@hotma il.com>
wrote:


fun4 (T**); // pointer-to-pointer-to-type-T yes.
fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T

Nope, just pointer-to-pointer-to-T.

fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T

Still just pointer-to-pointer-to-T.

Granted that I made a mistake in my notation here as Andrey pointed out. The
correct way to say this is
fun (T**); // pointer-to-pointer-to-type-T
fun (T(*)[2]); // pointer-to-array-of-size-2-of-type-T
fun (T(*)[3]); // pointer-to-array-of-size-3-of-type-T
I may be mistaken but from reading your post it seems to me that you are
under the impression that the 3 functions can't be overloaded as above. But
they can. There is a real honest to goodness (lol) type
pointer-to-array-of-size-3-of-type-T that does not decay to anything.
...

void fun (T **x) { cout << "fun1"; }
void fun (T (*x)[2]) { cout << "fun2"; }
void fun (T (*x)[3]) { cout << "fun3"; }
int main() {
T (*a)[2];
T (*b)[3];
T (*c)[4];
T **d;
fun(a); // call fun2
fun(b) ; // call fun3
fun((T**)(c)) ; // call fun1 (unsafe)
fun(d) ; // call fun1
}
...

As I said above, even if this would be an overall improvement to the
language (and I'm not saying it would be; I haven't completely thought it
through, and I'm not likely to), it would no longer be C or C++ and thus
could not possibly be worth breaking most of the existing C/C++ code base
to effect.


Try compiling the code that I gave above. It really does compile and run
with obvious modifications (e.g. if replace T with say 'int'). Also Andrey
answered my question in a very surprising way. You can coerce the compiler
to do array type checking for you. I just don't see why you have to jump
through hoops to do it. But the following code does exactly what I thought
can't be done--but i'm learning :)

#include<iostre am>
void fun(int *&x) {std::cout << "fun1" << std::endl;}
void fun(int (&x)[2]) {std::cout << "fun2" << std::endl;}
void fun(int (&x)[3]) {std::cout << "fun3" << std::endl;}
int main() {
int aa[2];
int bb[3];
int cc[4];
fun(aa); // fun2
fun(bb); // fun3
int *p_cc=cc; // manual decay
fun(p_cc); // fun1
}

Alas you need that "manual decay" :( But on the bright side I qualified endl
with std namespace :)

Jul 22 '05 #6
On Wed, 12 May 2004 00:48:38 GMT, "Canonical Latin"
<ja******@hotma il.com> wrote:
It is not exactly correct. Compiler sees array-of-size-N-of-type-T as
pointer-to-type-T in case of function parameter declaration. The rest
follows. This is specific to situations when one makes syntactical
attempt to pass arrays "by value".

Note, that if you declare your functions as

fun (T (&x)[2]); // fun2
fun (T (&x)[3]); // fun3

That is great. It is almost there. The only problem is that now you cannot
have
fun (T x[]); // fun1
and call it with
T xx[4];
fun(xx);


Yes you can. You can have overloads for array ones and pointer ones.
Hmm.. I don't exactly understand what you are trying to say here.

I'm not sure I do either, but I try! Here is another attempt: as it is,
array-of-size-N-of-type-T decays to pointer-of-type-T when not argument to
sizeof and as you noted not qualified by &. Lets say I want array type
checking and still want to be able to pass T[N] to a function that does not
specify the N value e.g.
fun(T *x); // funA
fun(T (&x)[2]); // funB
main() {
T x[3] ;
fun(x) ; // funA
}
So the compiler tries to find fun(T (&x)[3]) and since it can't then it
automaticall y looks for fun(T *x); // funA


Yes that will work (once you add the int returns back in - implicit
int return is an old C feature, never a C++ one, although some
compilers have supported it for backwards compatibility reasons).

For the ultimate:

template <int N>
void fun(T (&x)[N])
{
//N gives the size of the array!
}

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #7
On Wed, 12 May 2004 04:51:51 GMT, "Canonical Latin" <ja******@hotma il.com>
wrote:
"Leor Zolman" <le**@bdsoft.co m> wrote in message
news:om******* *************** **********@4ax. com...
On Tue, 11 May 2004 22:01:40 GMT, "Canonical Latin" <ja******@hotma il.com>
wrote:
>
>
>fun4 (T**); // pointer-to-pointer-to-type-T yes.
>fun5 (T*[2]); // pointer-to-array-of-size-2-of-type-T

Nope, just pointer-to-pointer-to-T.
>
>fun6 (T*[3]); // pointer-to-array-of-size-3-of-type-T

Still just pointer-to-pointer-to-T.

Granted that I made a mistake in my notation here as Andrey pointed out. The
correct way to say this is
fun (T**); // pointer-to-pointer-to-type-T
fun (T(*)[2]); // pointer-to-array-of-size-2-of-type-T
fun (T(*)[3]); // pointer-to-array-of-size-3-of-type-T


And this post was written before Andrey's post came up; it was just delayed
for hours due to a news server glitch at my end, and I eventually re-sent
it.
I may be mistaken but from reading your post it seems to me that you are
under the impression that the 3 functions can't be overloaded as above.
I was, and still am, if you're talking about the exact way you posted them
above (as opposed to your corrected version down below). Try compiling this
(and if it works, please tell me what compiler you're using):

#include <iostream>
using namespace std;

typedef int T;

void fun (T x[]) {cout << "fun(T x[])" << endl; }
void fun (T x[2]) {cout << "fun(T x[2])" << endl; }
void fun (T x[3]) {cout << "fun(T x[3])" << endl; }

int main() {
T a[2];
T b[3];
T c[4];
T *d;

fun(a); // call fun2
fun(b) ; // call fun3
fun(c) ; // call fun1 (see comment at end)
fun(d) ; // call fun1

return 0;
}

But
they can. There is a real honest to goodness (lol) type
pointer-to-array-of-size-3-of-type-T that does not decay to anything.
...
>
>void fun (T **x) { cout << "fun1"; }
>void fun (T (*x)[2]) { cout << "fun2"; }
>void fun (T (*x)[3]) { cout << "fun3"; }
>int main() {
> T (*a)[2];
> T (*b)[3];
> T (*c)[4];
> T **d;
> fun(a); // call fun2
> fun(b) ; // call fun3
> fun((T**)(c)) ; // call fun1 (unsafe)
> fun(d) ; // call fun1
>}
> ... As I said above, even if this would be an overall improvement to the
language (and I'm not saying it would be; I haven't completely thought it
through, and I'm not likely to), it would no longer be C or C++ and thus
could not possibly be worth breaking most of the existing C/C++ code base
to effect.


Try compiling the code that I gave above. It really does compile and run
with obvious modifications (e.g. if replace T with say 'int').


Yes, I know; by "this" I meant having it allow overloads such as in the
example code I just gave you above (which doesn't compile for me.)

Also Andrey
answered my question in a very surprising way. You can coerce the compiler
to do array type checking for you. I just don't see why you have to jump
through hoops to do it. But the following code does exactly what I thought
can't be done--but i'm learning :)

#include<iostr eam>
void fun(int *&x) {std::cout << "fun1" << std::endl;}
void fun(int (&x)[2]) {std::cout << "fun2" << std::endl;}
void fun(int (&x)[3]) {std::cout << "fun3" << std::endl;}
int main() {
int aa[2];
int bb[3];
int cc[4];
fun(aa); // fun2
fun(bb); // fun3
int *p_cc=cc; // manual decay
fun(p_cc); // fun1
}

Yup, there are certainly ways to do what you're trying to do. The issue I
thought I was discussing was the suggestion that C++ should work
differently than it does when it comes to array names appearing as function
arguments, and the decay that entails. As long as you're not still wanting
that to happen, I've no qualms with any of the rest!
Alas you need that "manual decay" :( But on the bright side I qualified endl
with std namespace :)


:-)
-leor

--
Leor Zolman --- BD Software --- www.bdsoft.com
On-Site Training in C/C++, Java, Perl and Unix
C++ users: download BD Software's free STL Error Message Decryptor at:
www.bdsoft.com/tools/stlfilt.html
Jul 22 '05 #8

"tom_usenet " <to********@hot mail.com> wrote in message
news:vn******** *************** *********@4ax.c om...
On Wed, 12 May 2004 00:48:38 GMT, "Canonical Latin"
<ja******@hotma il.com> wrote:
.... Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html


I appreciate the pointers Tom, no pun intended. Just to summarize: My
question was "what is the rational of c++ not having typed arrays in
function calls" and your reply was "But it does if you are careful with
syntax such as:"
template <class T, int N>
void fun(T (&x)[N]) {
std::cout << N << std::endl;
}

Let's go back to function overloading. Surprisingly
int fun (int *x) {} //fun1
int fun (int (&x)[2]){} //fun2
int main() {
int x[2];
fun(x); // ambiguous
}
Does not compile (gcc 3.2.3). It complains about function call being
ambiguous. I don't understand why it is behaving this way, but I humor it
and fix the problem as
int fun (int *&x) {} //fun3
int fun (int (&x)[2]){} //fun2
int main() {
int x[2];
int y[3];
fun(x); // fun2
fun(y); // ambiguos
}
Now the compiler knows how to resolve fun(x) call, but gets stuck on fun(y)
being ambiguous. So I say "huh!" and try various casts on y in fun(y). But
uh-uh it ain't having none of that. So I sit and reason with it and say, hay
look
int fun (int *&x) {} //fun3
int fun (int (&x)[2]){} //fun2
int main() {
int x[2];
int y[3];
fun(x); // fun2
int *p = y;
fun(p); // fun3
}
Now it knows what I'm saying and grudgingly compiles my measly code. But
now, that new variable is a thorn on my side -- if I were looking at someone
else's code I would simply "clean it up". So after my long winded monolog I
come to the question: Suppose I want array type checking and also want
arrays that don't have a matching type to a function to be passed to a
default function (a la example above). Is there a clean way to do this?
Jul 22 '05 #9
Canonical Latin wrote:
So after my long winded monolog I
come to the question: Suppose I want array type checking and also want
arrays that don't have a matching type to a function to be passed to a
default function (a la example above). Is there a clean way to do this?


#include <ostream>
#include <iostream>
#include <string>

template <typename T, unsigned N>
void fun (T (& aref) [N])
{
std::cout << "default code\n";
}

template <typename T>
void fun (T (& aref) [3])
{
std::cout << "code for arrays of length 3\n";
}

template <unsigned N>
void fun (double (& aref) [N])
{
std::cout << "code for arrays of double\n";
}

void fun (double (& aref) [3])
{
std::cout << "resolve the ambiguity\n";
}

void test_drive ()
{
double a1 [4];
double a2 [3];
int a3 [4];
std::string a4 [3];

fun (a1);
fun (a2);
fun (a3);
fun (a4);
}

--
Regards,
Buster.
Jul 22 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
3369
by: Maximus | last post by:
Hi, I'd like to know if it's possible to allocate a multidimensional array during runtime using the new operator. I tried but VC tells me this: C:\Program Files\Microsoft Visual Studio\MyProjects\asdf\asdf.cpp(9) : error C2440: '=' : cannot convert from 'int (*)' to 'int *' Types pointed to are unrelated; conversion requires...
9
2609
by: Till Crueger | last post by:
Hi, I have to implement some simple sorting algorithm. I am NOT asking for you to do my homework, but my question is rather on how to store the integers. I recall reading once in here that there is a maximum value the operator has to accept. Since the programm should accept almost any number of integers, I am not sure if this limit will be...
22
2287
by: Canonical Latin | last post by:
#include<iostream> int main() { char buff; std::cin.getline(buff,3); std::cin.getline(buff,3); std::cout << buff << endl; } Run at command prompt and input 1234567 what do you get as output?
21
3900
by: Matteo Settenvini | last post by:
Ok, I'm quite a newbie, so this question may appear silly. I'm using g++ 3.3.x. I had been taught that an array isn't a lot different from a pointer (in fact you can use the pointer arithmetics to "browse" it). So I expected that when I run this program, I get both c1.A and c2.A pointing to the same address, and changing c1.A means that also...
7
7502
by: Rennie deGraaf | last post by:
A question regarding this code, which defines a struct containing a size and a variable-sized array: typedef struct { uint16_t count; unsigned char bytes; } foo_t; ....
1
2193
by: rir3760 | last post by:
Since a few days ago I have been working with the program I post below (a school assignment). The purpose of the program is to work with the va_ macros (stdarg.h) and arrays of arrays, hopefully learning a little bit in the process. The objective of the fn_memset function is to set all the chars in the arrays passed (of type array N of...
39
19571
by: Martin Jørgensen | last post by:
Hi, I'm relatively new with C-programming and even though I've read about pointers and arrays many times, it's a topic that is a little confusing to me - at least at this moment: ---- 1) What's the difference between these 3 statements: (i) memcpy(&b, &KoefD, n); // this works somewhere in my code
11
1931
by: Sunny | last post by:
#include <iostream> int main() { int len; std::cin >len; int Arr; int *p = new int; Arr=5; std::cout << &len << " " << &Arr << " " << p << std::endl;
29
35401
weaknessforcats
by: weaknessforcats | last post by:
Arrays Revealed Introduction Arrays are the built-in containers of C and C++. This article assumes the reader has some experiece with arrays and array syntax but is not clear on a )exactly how multi-dimensional arrays work, b) how to call a function with a multi-dimensional array, c) how to return a multi-dimensional array from a function,...
0
7420
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
7680
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7934
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
6003
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5349
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
4966
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3476
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1908
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
0
731
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.