Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

templates

3 views
Skip to first unread message

asaf morad

unread,
Mar 15, 2003, 7:00:50 PM3/15/03
to
is that legal in c++

template <int N>

void Size(int [][N])

{

cout << N;

}


[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

LLeweLLyn

unread,
Mar 16, 2003, 4:35:41 AM3/16/03
to
"asaf morad" <ass...@bezeqint.net> writes:

> is that legal in c++
>
> template <int N>
>
> void Size(int [][N])
>
> {
>
> cout << N;
>
> }

After adding the obvious #includes, using declaration, etc, the above is
well-formed C++.

Hyman Rosen

unread,
Mar 16, 2003, 4:38:31 AM3/16/03
to
asaf morad wrote:
> is that legal in c++
> template <int N> void Size(int [][N]) { cout << N; }

It is once you include <iostream> and use std::cout.

Ivan Vecerina

unread,
Mar 16, 2003, 5:17:29 AM3/16/03
to
"asaf morad" <ass...@bezeqint.net> wrote in message
news:3e73...@news.bezeqint.net...
: is that legal in c++

:
: template <int N>
: void Size(int [][N])
: {
: cout << N;
: }

Yes. It is indeed equivalent to the following signature:
void Size(int (*)[N])
(taking a pointer to an array whose size is defined by N).

The following alternative allows to access both bounds of
a 2D array passed as a parameter, by taking a reference to it:
template <int M, int N>
void Size(int (&)[M][N])
{
// ...
}

Regards,
--
Ivan Vecerina, Dr. med. <> http://www.post1.com/~ivec
Soft Dev Manger, XiTact <> http://www.xitact.com
Brainbench MVP for C++ <> http://www.brainbench.com

James Kanze

unread,
Mar 16, 2003, 6:13:00 PM3/16/03
to
Hyman Rosen <hyr...@mail.com> writes:

|> asaf morad wrote:
|> > is that legal in c++
|> > template <int N> void Size(int [][N]) { cout << N; }

|> It is once you include <iostream> and use std::cout.

No it's not. You also have to include <ostream>.

--
James Kanze mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France Tel. +33 1 41 89 80 93

asaf morad

unread,
Mar 17, 2003, 4:15:07 PM3/17/03
to
can someone tell me what is illegal in that ?

template <class T, int Dim>

class Array1D

{

public:

T& operator [] (int index) { return elems[index]; }

private:

T elems[Dim];

};

template <class T, int Dim1, int Dim2>

class Array2D

{

public:

Array1D<T, Dim2>& operator [] (int index) { return elems[index]; }

private:

// error C2233: '<Unknown>' : arrays of objects containing zero-size arrays
are illegal

Array1D<T, Dim2> elems[Dim1];

};

tom_usenet

unread,
Mar 17, 2003, 4:22:28 PM3/17/03
to
On 16 Mar 2003 18:13:00 -0500, James Kanze <ka...@alex.gabi-soft.fr>
wrote:

>Hyman Rosen <hyr...@mail.com> writes:
>
>|> asaf morad wrote:
>|> > is that legal in c++
>|> > template <int N> void Size(int [][N]) { cout << N; }
>
>|> It is once you include <iostream> and use std::cout.
>
>No it's not. You also have to include <ostream>.

I disagree. <iostream> declares std::cout, so std::basic_ostream<char>
must be a complete type, which means that using
basic_ostream<char>::operator<<(int) will be ok. Did I miss something?
You only need to #include <ostream> if you want to use the non-members
declared there...

Tom

James Kanze

unread,
Mar 18, 2003, 5:27:23 AM3/18/03
to
tom_u...@hotmail.com (tom_usenet) wrote in message
news:<3e75b0ad....@news.easynet.co.uk>...

> On 16 Mar 2003 18:13:00 -0500, James Kanze <ka...@alex.gabi-soft.fr>
> wrote:

> >Hyman Rosen <hyr...@mail.com> writes:

> >|> asaf morad wrote:
> >|> > is that legal in c++
> >|> > template <int N> void Size(int [][N]) { cout << N; }

> >|> It is once you include <iostream> and use std::cout.

> >No it's not. You also have to include <ostream>.

> I disagree.

With what the standard says?

> <iostream> declares std::cout, so std::basic_ostream<char> must be a
> complete type,

You don't need a complete type to declare something, only to define it
(and <iostream> doesn't define std::cout) -- the most obvious
implementation is, in fact:

#include <iosfwd>
namespace std {
extern istream cin ;
extern ostream cout ;
// ...
}

In fact, I think that the implementation is allowed to use compiler
magic so that std::cout is known although the compiler knows nothing
about its type; in this case, not even the include of <iosfwd> is
necessary.

> which means that using basic_ostream<char>::operator<<(int) will be
> ok. Did I miss something?

Two things: see above.

> You only need to #include <ostream> if you want to use the non-members
> declared there...

That's another alternative -- that the implementation in fact defines
basic_ostring in a separate file, included from both <iostream> and
<ostream>. In this case, you get a different overload set for
operator<<.

I find the situation deplorable, and I much prefer the situation in C,
where a standard header may ONLY define what is specified in the
standard, and cannot include other standard headers. In practice,
however, I think this would cause implementation problems in C++
(although perhaps something like the solution concerning NULL in C could
be made to work).

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique oriente objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, Tl. : +33 (0)1 30 23 45 16

Maciej Sobczak

unread,
Mar 18, 2003, 5:29:51 AM3/18/03
to
Hi,

"tom_usenet" <tom_u...@hotmail.com> wrote in message
news:3e75b0ad....@news.easynet.co.uk...

> I disagree. <iostream> declares std::cout, so std::basic_ostream<char>
> must be a complete type

Recent thread about this has revealed only some suspicion that it is
possible to declare std::cout without defining std::basic_ostream template
class, but the constructuve example was not given (or I've missed some
posts).

What about the fact that <iostream> header is supposed to declare the
std::cin, std::cout, etc. as *extern* symbols?

The 7.1.1/8 says:
"The name of a declared but undefined class can be used in an extern
declaration. Such a declaration can only be used in ways that do not require
a complete class type."

Consider:

// only declared!
template <typename T>
class MyClass;

extern MyClass<int> symbol;

This is what poor-man's <iostream> could do.
Want to fully use "symbol"? Include additionally the definition of MyClass
(<ostream>).

Without going into such details, the catch is also that standard headers do
not have to exist in the form of a source code at all -- they do not even
have to exist as files on your hard drive. With this assumption, the
#include <iostream> can only switch on some symbols in the compiler --
whether it should also switch on the std::basic_ostream symbol with all its
internals is just a speculation.

Anyway, this issue (the whole <iostream> thing) is my vote for the best
catch ever. ;)
It may be a good candidate for DR as well.

--
Maciej Sobczak
http://www.maciejsobczak.com/

Distributed programming lib for C, C++, Python & Tcl:
http://www.maciejsobczak.com/prog/yami/

Hyman Rosen

unread,
Mar 18, 2003, 12:00:52 PM3/18/03
to
asaf morad wrote:
> can someone tell me what is illegal in that ?

Nothing? Comeau accepts this code.

tom_usenet

unread,
Mar 18, 2003, 4:12:02 PM3/18/03
to
On 18 Mar 2003 05:27:23 -0500, ka...@gabi-soft.de (James Kanze) wrote:

>tom_u...@hotmail.com (tom_usenet) wrote in message
>news:<3e75b0ad....@news.easynet.co.uk>...
> > On 16 Mar 2003 18:13:00 -0500, James Kanze <ka...@alex.gabi-soft.fr>
> > wrote:
>
> > >Hyman Rosen <hyr...@mail.com> writes:
>
> > >|> asaf morad wrote:
> > >|> > is that legal in c++
> > >|> > template <int N> void Size(int [][N]) { cout << N; }
>
> > >|> It is once you include <iostream> and use std::cout.
>
> > >No it's not. You also have to include <ostream>.
>
> > I disagree.
>
>With what the standard says?

With your interpretation of the standard. But not any more!

>
> > <iostream> declares std::cout, so std::basic_ostream<char> must be a
> > complete type,
>
>You don't need a complete type to declare something, only to define it
>(and <iostream> doesn't define std::cout) -- the most obvious
>implementation is, in fact:
>
> #include <iosfwd>
> namespace std {
> extern istream cin ;
> extern ostream cout ;
> // ...
> }

Doh! I completely forgot that extern doesn't require a complete type.
However, according to the synopsis, you *can* rely on the typedefs
istream, ostream, etc. being available - IOW, a small chunk of
<iosfwd> will be "included" since I assume the synopsis is normative.

>
>In fact, I think that the implementation is allowed to use compiler
>magic so that std::cout is known although the compiler knows nothing
>about its type; in this case, not even the include of <iosfwd> is
>necessary.
>
> > which means that using basic_ostream<char>::operator<<(int) will be
> > ok. Did I miss something?
>
>Two things: see above.
>
> > You only need to #include <ostream> if you want to use the non-members
> > declared there...
>
>That's another alternative -- that the implementation in fact defines
>basic_ostring in a separate file, included from both <iostream> and
><ostream>. In this case, you get a different overload set for
>operator<<.

Yes, that is the case I was thinking of, thinking that <iostream>
needed basic_ostream<char>.

There is quite a large chunk of implementation defined behaviour
caused by this header issue. e.g. if you #include <fstream> you don't
necessarily get the <i/ostream> globals, potentially jiggling with
your overloads as you say.

>I find the situation deplorable, and I much prefer the situation in C,
>where a standard header may ONLY define what is specified in the
>standard, and cannot include other standard headers. In practice,
>however, I think this would cause implementation problems in C++
>(although perhaps something like the solution concerning NULL in C could
>be made to work).

It makes sense to make use of standard algorithms in various places in
container implementations. And map and set obviously require std::pair
from <utility> and std::allocator from <memory>, etc, etc. It might be
an interesting project to work out the minimal guaranteed set of names
that must be brought in by each standard header. e.g. iostream brings
in:

cin, cout, (other stream objects), istream, ostream, (wide versions),
basic_istream, basic_ostream, and I think that's it, with none of the
types necessarily being complete.

vector brings in:
vector, allocator, reverse_iterator, size_t?, ptrdiff_t?, etc., etc.

Tom

Kevin Cline

unread,
Mar 19, 2003, 4:18:53 AM3/19/03
to
"asaf morad" <ass...@bezeqint.net> wrote in message news:<3e73...@news.bezeqint.net>...
> is that legal in c++
>
> template <int N>
>
> void Size(int [][N])
>
> {
>
> cout << N;
>
> }

Yes, but it doesn't work in Visual C++ version 6.
Nor does this:

template <int N>
int Size(int (&a)[N]) { return N; }

James Kanze

unread,
Mar 19, 2003, 7:01:42 PM3/19/03
to
tom_u...@hotmail.com (tom_usenet) wrote in message
news:<3e772f2d....@news.easynet.co.uk>...

> >I find the situation deplorable, and I much prefer the situation in
> >C, where a standard header may ONLY define what is specified in the
> >standard, and cannot include other standard headers. In practice,
> >however, I think this would cause implementation problems in C++
> >(although perhaps something like the solution concerning NULL in C
> >could be made to work).

> It makes sense to make use of standard algorithms in various places in
> container implementations. And map and set obviously require std::pair
> from <utility> and std::allocator from <memory>, etc, etc.

Yes, but the standard algorithms should only be used in the
implementation, which should be exported (so you don't see the
inclusion). The legality of your code should not depend on
implementation details.

The case where one definition is based on another (such as std::map
depending on std::pair) is different. The C standard handles this by
saying that e.g. NULL is defined in several different headers.
Something like this is conceivable, although the number of such
dependancies in C++ make it considerably more complex.

> It might be an interesting project to work out the minimal guaranteed
> set of names that must be brought in by each standard
> header. e.g. iostream brings in:

> cin, cout, (other stream objects), istream, ostream, (wide versions),
> basic_istream, basic_ostream, and I think that's it, with none of the
> types necessarily being complete.

The standard does this. For example, iostream guarantees the presence
of std::cin, std::cout, std::cerr, std::clog, std::wcin, std::wcout,
std::wcerr and std::wclog. And nothing else.

Sort of, because most of the library definition is in terms of C++ code,
and the code defining the contents of <iostream> *uses* the symbols
istream, ostream, wistream and wostream. It is not clear to me how much
the compiler is required to make visible of these symbols, however.
(Remember, compiler magic is allowed in standard headers.)

The header declares the eight names. That is all. And either it
shouldn't be allowed to declare any others, or it should be required to
declare them. Or (what I think some people want) it should be required
to define them. Or maybe define them along with all of the overloads
specified in <istream> and <ostream>. At any rate, which symbols are
pulled in by <iostream>, and whether they are definitions or
declarations, should be strictly defined by the standard. (My own
preference for <iostream> would be that it is the exact equivalent of
the text in §27.3, preceded by an "#include <iosfwd>". And that
<iosfwd> is required to be the exact equivalent of the text in §27.2.)

> vector brings in: vector, allocator, reverse_iterator, size_t?,
> ptrdiff_t?, etc., etc.

Does it bring in the headers that contain them, or just define the
symbols it needs? Can I count on all of <cstddef> being present after
an include of <vector>, or only on size_t and ptrdiff_t?

The C standard takes the latter approach. With the result that things
like NULL and size_t must be defined in several different headers (with
some mechanism to avoid multiple definitions when several of the headers
are included). The C standard can do this partially because the number
of symbols involved is very limited, and their definitions are extremely
simple (just a #define or a typedef). While I'd like to see something
similar for C++, I'm not sure it is feasable; it would probably be an
implementors nightmare.

--
James Kanze GABI Software mailto:ka...@gabi-soft.fr

Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, Tél. : +33 (0)1 30 23 45 16

0 new messages