Topic: signatures or interfaces in C++
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/04/15 Raw View
Pierre Baillargeon wrote:
[...]
> My original idea, which I'll revert to now, is to treat the user-defined
> qualifiers just like "const". So that your example would turn into:
>
> qualifier sorted;
> template <class T> sorted std::vector<T> & sort ( std::vector<T> & );
> template <class T> std::vector<T> & scramble ( std::vector<T> & );
>
> void f(sorted vector<i> &); // 1.
> void f(vector<i> &); // 2.
>
> // Note: f 2. could take sorted or non-sorted vectors just as if
> // the "sorted" qualifier was the "const" qualifier,
> // but the overload of f 1. prevents this.
But that's not the semantics of const:
void f2(vector<i> const&); // 1'
void f2(vector<i>&); // 2'
Now f2 1' can take both const and non-const vectors, while f2 2'
only can take non-const vectors. Therefore with const semantics,
f 1. could take both sorted and unsorted vectors, while f 2.
could take only unsorted ones. The overload prevents f 1. to
take unsorted vectors, though.
That is, a reference to vector<T> sorted would not say
"this is sorted", but "this _may_ be sorted - don't do anything
which may destroy the order". OTOH, an unsorted access path
means "this object may be considered unsorted, you may
destroy the order".
Especially, a function could _not_ take advantage of the
vector being sorted, since it doesn't know if it is.
Any const-like qualifier has the semantics of a restriction;
in access paths qualifier foo just means "this _may_ be
foo; don't do anything which may not be done for foo objects"
(f.ex. optimize away accesses for volatile; modify
for const; scramble for sorted).
Another problem with const-like qualifiers is that they
are not in the implicitly declared copy constructor
and copy assignment operator. Note that this problem
even exists for the already-existing qualifier "volatile".
Unless I'm mistaken, the following code is illegal:
class X {};
X a;
X volatile b;
a = b; // Error: attempt to bind volatile object to
// non-volatile reference
Also, adding a new const-like qualifier foo would cause
all previously written code to be not "foo-correct".
Now, the const-correctness problem is well known, but
given that const is in the standard, one can expect
all functions to be const-correct sooner or later.
OTOH, you cannot expect third-party libraries foo-correct
if you just invented the foo qualifier.
The idea of user-defined qualifiers is nice; however
global qualifiers with const semantics don't work well.
However, I think you can save the idea with a simple
change: Instead of allowing global qualifiers, the
qualifiers to be used with a class must be declared
within the class definiiton (this makes sense, since most
often a qualifier is meaningless on arbitrary types - what
is a sorted int?). Then all possible qualifiers are known
when the implicit copy constructor/copy assignment are
generated, and therefore it's easy to demand that the
implicitly declared functions take the appropriate
qualified reference (i.e. all qualifiers declared to be
used for that class are to be used, unless a member or
base class _which also declares that qualifier_ doesn't have
it in it's copy definition). The const qualifier would be
seen as implicity declared, and the volatile qualifier could
be explicily mentioned if the implicitly generated
functions should use it.
If in addition, constructors would be allowed to have
qualifiers to represent the qualifiers of the constructed
type, this could indeed be a very powerful concept:
qualifier sorted;
template<class T, int size> class array
{
public:
using qualifier sorted;
// required to allow use of that qualifier with array
array() sorted // also called for unsorted containers
{
std::fill(data, data+size, T());
}
array(array sorted const& other) // can only called by unsorted
containers
{ // but doesn't care if arg is sorted
std::copy(other.data, other.data+size, data);
}
array(array const& other) sorted // only called by sorted arrays
{ // if copying unsorted arrays
std::copy(other.data, other.data+size, data);
std::sort(data, data+size); // we must sort the data here
}
array(array sorted const& other) // called only for unsorted arrays
{ // but argument may be sorted or unsorted
std::copy(other.data, other.data+size, data);
}
// assignment, operators, ...
};
Now, you could do something like
int i[] = { 1, 3, 2 };
array<int, 3> sorted foo(i, 3); // gets { 1, 2, 3 } automatically
array<int, 3> bar(i, 3); // gets { 1, 3, 2 }
bar = foo; // just copying
foo = bar; // copying bar and then sorting foo
This would also allow definition of const constructors
without being incompatible with the current language:
If const is not explicitly given in the using qualifier
line, then all constructors are considered const
constructors (same semantics as now), but if given, only
those marked const would be used for constructing
const objects; those without const would be used only for
non-const objects (and would be preferred if given, if
non-const objects are defined).
To be consistant, qualifiers in general should not apply
to *this in the constructor body.
I think destructors should not be qualifiable - there's
no value in requiring a destructor to be different for
sorted and possibly unsorted objects; in addition, the
access path with which the destructor is called may not
reflect the real qualification of object (for example,
an unsorted object may be accessed through a sorted
access path - which just means that the object _may_ be
sorted).
Another point is qualification casting.
The most logical thing would be to allow const_cast to
modify all qualifications (it already modifies both const
and volatile). OTOH, this could be seen as confusing, and
a new qualification_cast could be introduced (which should
also be able to cast const and volatile).
>
> void foo()
> {
> std::vector<int> i;
> // fill i
>
> std::vector<int> * normal = 0;
> sorted std::vector<int> * sorted = 0;
>
> if (I_want_it_sorted)
> sorted = & sort(i);
> else
> normal = & scramble(i);
>
> // is i now sorted? *NO*
>
> f(i); // f 2. is called.
> if (normal)
> f(*normal); // f 2. is called.
> if (sorted)
> f(*sorted); // f 1. is called.
> }
>
> So once again, changing one's idea at the last moment while writing a
> post is a *bad* idea!
Well, I often _develop_ ideas while writing a post ;-)
(Well, if you'd see my folder of unsent posts... ;-))
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Zorba the Hutt" <kryten@halcyon.com>
Date: 2000/04/18 Raw View
Wouldn't you know it, I write this whole long thing and manage to miss one
of the points I wanted to make.
Dealing with a new qualifier like "sorted": Conceptually speaking, "sorted"
makes perfect sense as a (compiletime-derived) class. The qualifier requires
the class to make changes in how it handles incoming data (i.e. "place in
order" as opposed to "place at the end of the list 'cause it's faster") and
may make changes in how it can handle outgoing data (i.e. searches can be
done by bisecting the array repeatedly instead of just testing every item).
So, one could presumably make a "status class" (a completely empty class
designed only for the purpose of providing a compiler flag) called "sorted",
then either explicitly compiletime-derive from "sorted" and "datacontainer"
or could just use a combo-class requirement of "sorted" and "datacontainer".
Both of which would cheerfully resolve at compiletime, and thus provide no
speed losses.
-Zorba
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/04/12 Raw View
kanze@gabi-soft.de wrote:
>
> Pierre Baillargeon <pb@artquest.net> writes:
>
> |> What I find interesting in this is the fact that we are now, relative to
> |> templates, in a situation much like the one of K&R C, relative to
> |> functions.
>
> This is only partially true. If you make a mistake in using the
> template interface, you will normally get a compile time error. The
> error text will probably be misleading, but at least, the results won't
> be undefined runtime behavior.
This is only partially true.
The problem arises if an algorithm doesn't make use of all
required operations. For example:
template<class ForwardIterator>
Forward_iterator find(ForwardIterator first,
ForwardIterator last,
typename ForwardIterator::value_type v)
{
while (first != last && *first != v)
++first;
return first;
}
Now assume someone writes a forward iterator, but forgets
postfix operator++. Now he calls this implementation of find,
and indeed, it compiles and runs and gives the expected result.
Then he delivers the code, and someone else uses another
implementation (or even another version of the same
implementation), where find is implemented as
template<class ForwardIterator>
Forward_iterator find(ForwardIterator first,
ForwardIterator last,
typename ForwardIterator::value_type v)
{
while (first != last && *first++ != v);
return first;
}
And now the code - which compiled and ran OK on the other
implementation, will suddenly stop working.
OK, there are workarounds; f.ex.
template<class ForwardIterator>
Forward_iterator find(ForwardIterator first,
ForwardIterator last,
typename ForwardIterator::value_type v)
{
if (0) // check requirements
{
typedef typename ForwardIterator::value_type value_type;
first++;
++first;
first == last;
first != last;
value_type v2 = *first++;
*first==v;
ForwardIterator iter(first);
iter = first;
}
while (first != last && *first != v)
++first;
return first;
}
I'd expect any good compiler to optimize out the if(0) part;
you could even pack that into a macro:
#define CHECK_REQUIREMENTS(Req, Type) if(0) Req(Type)
#define INPUT_ITERATOR_REQIREMENTS(Iter) \
{ \
typedef typename Iter::value_type value_type; \
Iter i1, i2(i1); \
i1 = i2; \
value_type v = *i1; \
++i1; \
i1++; \
v = *++i1; \
v = *i1++; \
bool b(i1 == i2); \
b = (i1 != i2); \
}
template<class ForwardIterator> void foo(...)
{
CHECK_REQUIREMENTS(INPUT_ITERATOR_REQUIREMENTS, ForwardIterator)
...
}
However, wouldn't it be much cleaner to write
template<class Iterator: ForwardIterator> void foo(...)
{
...
}
?
Such concepts should IMHO support inheritance ("is-a" makes
at least as much sense for concepts as for classes); one could
even allow classes to inherit from concepts (the difference
to Java's "implements" would be that classes don't _need_ to
be derived from a concept to be an instance of it. Instead,
deriving would be just a way to let the compiler ensure that
the concept requirements are met.
Another difference between concepts and Java interfaces is
that I think concepts should not provide signatures (as done
with Java interfaces and g++ signatures), but operations
(similar to the standard requirements tables). That is, it
should, just as the CHECK_REQUIREMENTS macro above, contain
code that must compile. For example, the iterator concepts
could read:
concept InputIterator
{
typedef typename InputIterator::value_type value_type;
InputIterator i1, i2(i1);
i1 = i2;
value_type v = *i1;
++i1;
i1++;
v = *++i1;
v = *i1++;
bool b(i1 == i2);
b = (i1 != i2);
};
concept OutputIterator
{
// ...
};
concept ForwardIterator: InputIterator
{
// additional requirements
};
concept BidirectionalIterator: ForwardIterator
{
// ...
};
concept RandomAccessIterator: BidirectionalIterator
{
// ...
};
Now, there could be a sort of partial ordering based on
concept inheritance. Partial ordering based on "concept
coverage" would be nicer, but probably very hard to
implement (you would have to rigorously check that every
type that allows snippet 1 to compile also allows snippet 2
to compile; this should be difficult, if not impossible).
That is, you could write:
template<class Iterator: ForwardIterator>
void rotate(Iterator first, Iterator mid, Iterator last)
{
// ...
}
template<class Iterator: BidirectionalIterator>
void rotate(Iterator first, Iterator mid, Iterator last)
{
// ...
}
template<class Iterator: RandomAccessIterator>
void rotate(Iterator first, Iterator mid, Iterator last)
{
// ...
}
On template instantiations, a template is only a candidate,
if the "concept proof code" compiles for the deduced type(s).
And then a partial ordering dependent on concept inheritance
would be applied, similar to the overload resolution for
derived classes (the concept definition doesn't matter at
this stage, since all templates that don't fit have been
ruled out from the first step; just treat the class as
inherited from all concepts which are used in the template
definition(s)).
That is, if someone tries to instantiate the rotate template
above with a bidirectional iterator, the compiler will first
- with the current selection rules - determine the set of
templates to consider (in this case, it's only those given
above). Then for each template where a concept is given,
the compiler tries to compile the concept-defining code
(without emitting anything; just to check compilability),
and if it doesn't compile, the type doesn't fit the concept
and therefore the template is removed from the set. In the
bidirectional iterator case, only the random access iterator
would be removed. Then the usual partial ordering rules would
apply, with the extra rule that if two templates differ only
in their concept constraints, and the concept constraints
of one are all the same or derived from the concept constraints
from another with at least one being not the same, the first
template is better.
Note that this partial ordering is exactly what is emulated
with the iterator_tags hierarchy, except that
- the iterator-tag does in no way guarantee that the iterator
really conforms to the corresponding iterator requirements,
and the compiler cannot check for programming errors, unless
the corresponding operation is indeed used by the algorithm.
- the mechanism works with an extra template function which
translates the concept hierarchy into the tag hierarchy
(on some compilers, this may hinder some optimisations;
also, it's just more complex for the reader). The concept
extension would make this unnecessary and therefore reduce
programming errors.
Of course, only the static parts of the concept can really be
checked; there's f.ex. no way to prove statically that a
bidirectional iterator is unchanged by (++i,--i) if ++i is
allowed. But the concept extension would allow
- to statically assure that a class really conforms to
a concept, by "inheriting" the concept.
- to statically assure that a template parameter really
conforms to a concept.
- to overload templates on concepts, allowing different
implementations for different concepts, without resorting
to a mechanism like iterator tags.
Note that the last one could also be interesting for classes.
For example:
concept FrontInsertionSequence
{
FrontInsertionSequence s;
typename FrontInsertionSequence::value_type v(s.front());
s.push_front(v);
s.pop_front();
}
concept BackInsertionSequence
{
BackInsertionSequence s;
typename BackInsertionSequence::value_type v(s.front()), v2(v);
s.front() = v;
s.push_back(v);
s.pop_back();
}
concept FrontAndBackInsertionSequence:
FrontInsertionSequence, BackInsertionSequence
{
}
template<class Sequence: FrontInsertionSequence> class Stack
{
public:
typedef typename Sequence::value_type value_type;
void push(value_type const& v) { seq.push_front(v); }
void pop() { seq.pop_front(); }
v& top() { return seq.front(); }
private:
Sequence seq;
};
template<class Sequence: BackInsertionSequence> class Stack
{
public:
typedef typename Sequence::value_type value_type;
void push(value_type const& v) { seq.push_back(v); }
void pop() { seq.pop_back(); }
v& top() { return seq.back(); }
private:
Sequence seq;
};
template<class Sequence: FrontAndBackInsertionSequence> class Stack
{
public:
typedef typename Sequence::value_type value_type;
void push(value_type const& v) { seq.push_back(v); }
void pop() { seq.pop_back(); }
v& top() { return seq.back(); }
private:
Sequence seq;
};
This template would actually be more useful than the stack
template of the standard library, since it would hide the
difference between front insertion and back insertion.
(While the standard library itself doesn't have a pure front
insertion sequence, the SGI STL does: slist<>. slist would
be sufficient for implementing a stack; however, since
std::stack needs a back insertion sequence, it doesn't work
with slist.
The last example shows that concepts should also provide
an "or" operation, to prevent doubling the code. This
could be done with a modified concept inheritance:
concept AtLeastBackInsertionSequence:
BackInsertionSequence | FrontAndBackInsertionSequence;
The partial ordering for those would be as follows:
- the or'ed concept has less priority than each of the
concepts or'ed together
- the or'ed concept has more priority than any base concept
of one of the or'ed together concepts, unless this base
concept or one of its base concepts is one of the concepts
or'ed together (that is, the first rule takes precedence).
- all concepts derived from that concept have also less
priority than any of the or'ed together concepts, unless
their position is moved by inheritance from other concepts
(that is, and-inheritance takes precedence over or-inheritance)
examples:
concept A { ... };
concept B { ... };
concept C { ... };
concept D: A { ... };
concept E: A, B { ... };
concept F: A | B;
concept G: F, C { ... };
concept H: A, F { ... };
concept I: E, F { ... };
concept J: G | H;
concept K: G | C;
Now the partial ordering is:
and-inheritance:
A<D, A<E, B<E, F<G, C<G, A<H, F<H, E<I, F<I
or-inheritance, rule 1:
F<A, F<B, J<G, J<H, K<G, K<C
or-inheritance, rule 2:
F<J, C<J, A<J, F<K (not C<K, since rule 1 takes precedence)
or-inheritance, rule 3:
G<A, G<B, H<B (not: H<A, I<A or I<B, since and-inheritance
takes precedence)
This is a total order, which can be represented f.ex. by
K = {1}
J = {2}
F = {3}
C = {1,4}
G = {1,2,3,4,5}
A = {1,2,3,4,5,6}
H = {1,2,3,4,5,6,7}
B = {1,2,3,4,5,6,7,8}
E = {1,2,3,4,5,6,7,8,9}
and (x < y) means x is true partial set of y.
I think the rules above should always result in a partial order;
I haven't checked however.
After all, the idea is that and-inheritance places the new
concept "directly above" the inherited concepts, while
or-inheritance places it "directly below". that is, all
concepts which are above or below the inherited concept(s)
are also above or below the new one, unless there's a
conflict, in which case and-inheritance wins.
[...]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pierre Baillargeon <pb@artquest.net>
Date: 2000/04/12 Raw View
Christopher Eltschka wrote:
>
> kanze@gabi-soft.de wrote:
> >
> > Pierre Baillargeon <pb@artquest.net> writes:
> >
> > |> What I find interesting in this is the fact that we are now, relative to
> > |> templates, in a situation much like the one of K&R C, relative to
> > |> functions.
> >
[...]
>
> However, wouldn't it be much cleaner to write
>
> template<class Iterator: ForwardIterator> void foo(...)
> {
> ...
> }
>
> ?
>
> Such concepts should IMHO support inheritance ("is-a" makes
> at least as much sense for concepts as for classes); one could
> even allow classes to inherit from concepts (the difference
> to Java's "implements" would be that classes don't _need_ to
> be derived from a concept to be an instance of it. Instead,
> deriving would be just a way to let the compiler ensure that
> the concept requirements are met.
> Another difference between concepts and Java interfaces is
> that I think concepts should not provide signatures (as done
> with Java interfaces and g++ signatures), but operations
> (similar to the standard requirements tables). That is, it
> should, just as the CHECK_REQUIREMENTS macro above, contain
> code that must compile. For example, the iterator concepts
> could read:
That is very close to what I had described on Slashdot, except your
description is much more complete and formalized. The only point where I
went further was that my description also included dynamic concepts that
could be acquired and lost. A better name for dynamic concepts would be
"qualifier".
The example I gave that related to C++ was the "const" qualifier. An
imaginary example would be a "sorted" qualifier, with functions
accepting or converting to a sorted qualified type. For example:
qualifier sorted;
template <class T> sorted std::vector<T> & sort ( std::vector<T> & );
The problem is that this would require the ability to divide a
posteriori all functions upon a qualifier. A good start would be to
consider all non-specified functions arguments as loosing a given
qualifier. Then provide a way to specify the qualification of each
argument of an already-declared function:
template <class T> void sort ( std::vector<T> & );
qualifier sorted;
qualify<sorted> template <class T> void sort ( +sorted std::vector<T> &
);
qualify<sorted> template <class T> void scramble ( -sorted
std::vector<T> & );
qualify<sorted> template <class T> void noop ( =sorted std::vector<T> &
);
So that sort() adds the sorted qualifier, scramble() looses it, and
noop() leave it as it is.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 2000/04/13 Raw View
Pierre Baillargeon wrote:
>
> Christopher Eltschka wrote:
> >
> > kanze@gabi-soft.de wrote:
> > >
> > > Pierre Baillargeon <pb@artquest.net> writes:
> > >
> > > |> What I find interesting in this is the fact that we are now, relative to
> > > |> templates, in a situation much like the one of K&R C, relative to
> > > |> functions.
> > >
>
> [...]
>
> >
> > However, wouldn't it be much cleaner to write
> >
> > template<class Iterator: ForwardIterator> void foo(...)
> > {
> > ...
> > }
> >
> > ?
> >
> > Such concepts should IMHO support inheritance ("is-a" makes
> > at least as much sense for concepts as for classes); one could
> > even allow classes to inherit from concepts (the difference
> > to Java's "implements" would be that classes don't _need_ to
> > be derived from a concept to be an instance of it. Instead,
> > deriving would be just a way to let the compiler ensure that
> > the concept requirements are met.
> > Another difference between concepts and Java interfaces is
> > that I think concepts should not provide signatures (as done
> > with Java interfaces and g++ signatures), but operations
> > (similar to the standard requirements tables). That is, it
> > should, just as the CHECK_REQUIREMENTS macro above, contain
> > code that must compile. For example, the iterator concepts
> > could read:
>
> That is very close to what I had described on Slashdot, except your
> description is much more complete and formalized. The only point where I
> went further was that my description also included dynamic concepts that
> could be acquired and lost. A better name for dynamic concepts would be
> "qualifier".
Could you please give me the URL of that text (or other data that
helps me find it on Slashdot)?
>
> The example I gave that related to C++ was the "const" qualifier. An
> imaginary example would be a "sorted" qualifier, with functions
> accepting or converting to a sorted qualified type. For example:
>
> qualifier sorted;
> template <class T> sorted std::vector<T> & sort ( std::vector<T> & );
>
> The problem is that this would require the ability to divide a
> posteriori all functions upon a qualifier. A good start would be to
> consider all non-specified functions arguments as loosing a given
> qualifier. Then provide a way to specify the qualification of each
> argument of an already-declared function:
>
> template <class T> void sort ( std::vector<T> & );
> qualifier sorted;
>
> qualify<sorted> template <class T> void sort ( +sorted std::vector<T> &
> );
> qualify<sorted> template <class T> void scramble ( -sorted
> std::vector<T> & );
> qualify<sorted> template <class T> void noop ( =sorted std::vector<T> &
> );
>
> So that sort() adds the sorted qualifier, scramble() looses it, and
> noop() leave it as it is.
I don't think that would work too well:
void f(sorted vector<i>);
void f(vector<i>);
void foo()
{
std::vector<int> i;
// fill i
if (I_want_it_sorted)
sort(i);
else
scramble(i);
// is i now sorted?
f(i); // which f should be called?
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pierre Baillargeon <pb@artquest.net>
Date: 2000/04/14 Raw View
Christopher Eltschka wrote:
>
> Could you please give me the URL of that text (or other data that
> helps me find it on Slashdot)?
I've never done searches on slashdot either, so I'll simply post it here
(the original was in HTML though). Remember, it was a question adressed
to Bjarne S.
-- start --
Reading the C++ newsgroup, you FAQ and an interview with A. Stepanov, I
had the following successive realizations:
- C++ templates don't allow someone to specify what is required out of
the template parameters.
- The specification is implicit, being how the template uses its
parameters.
- Implicit means it is hard to detect errors early or put constraints on
parameters.
- The implicitness of template is much like the implicitness of
functions in pre-prototype C.
- Your decision to add prototypes to functions in C++ not only avoided
common errors and allowed early diagnostics, but allowed overloading
and, later, templates!
- That is, you have to add the notion of prototypes to the language to
be able to tell the compiler that a function or class is overloaded or
templated!
- Adding contraints to C++ templates would not only allow early
diagnostics, but allow meta-templates.
- Some current designs use "dummy" parameters to allow some form of
constraints or flexibility (for example: traits).
- Saying that something is "const" is a form of constraint.
What I call meta-template is the ability to templatize the contraints
put on template parameters. I envision this with the added ability to
add "categorizing" template argument, where the programmer can specify
the relation of categories (inheritance) and conversion. Example of
simple categories: const, volatile, sorted. Then think about the
relation between const and non-const and apply to other categories.
So my question is: what do you think is the "next level" of generic
programming? Do you see such an evolution as I described, or something
else?
-- end --
> I don't think that would work too well:
>
> void f(sorted vector<i>);
> void f(vector<i>);
>
> void foo()
> {
> std::vector<int> i;
> // fill i
>
> if (I_want_it_sorted)
> sort(i);
> else
> scramble(i);
>
> // is i now sorted?
> f(i); // which f should be called?
> }
>
I changed my original example from "a function taking a reference to a
normal vector and returning a reference to a sorted vector" to the I
wrote and that you show, not realizing the fundamental difference. Also,
I changed some semantics in the process.
My original idea, which I'll revert to now, is to treat the user-defined
qualifiers just like "const". So that your example would turn into:
qualifier sorted;
template <class T> sorted std::vector<T> & sort ( std::vector<T> & );
template <class T> std::vector<T> & scramble ( std::vector<T> & );
void f(sorted vector<i> &); // 1.
void f(vector<i> &); // 2.
// Note: f 2. could take sorted or non-sorted vectors just as if
// the "sorted" qualifier was the "const" qualifier,
// but the overload of f 1. prevents this.
void foo()
{
std::vector<int> i;
// fill i
std::vector<int> * normal = 0;
sorted std::vector<int> * sorted = 0;
if (I_want_it_sorted)
sorted = & sort(i);
else
normal = & scramble(i);
// is i now sorted? *NO*
f(i); // f 2. is called.
if (normal)
f(*normal); // f 2. is called.
if (sorted)
f(*sorted); // f 1. is called.
}
So once again, changing one's idea at the last moment while writing a
post is a *bad* idea!
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pierre Baillargeon <pb@artquest.net>
Date: 2000/04/14 Raw View
Pierre Baillargeon wrote:
>
> if (I_want_it_sorted)
> sorted = & sort(i);
> else
> normal = & scramble(i);
>
> // is i now sorted? *NO*
>
Just a precision: when I say that "i" is not sorted, I mean that the
variable declaration is not changed by the calls and even though the
content might be sorted, the variable qualifier are not dynamically
changed. The returned value of the sort() call, "sorted", has the
"sorted" qualifier though.
I also realize that I declared a variable with the same name as the
qualifier. That may add some confusion to my example. No I didn't
compile the code before submitting! *grin*
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Zorba the Hutt" <kryten@halcyon.com>
Date: 2000/04/15 Raw View
"Pierre Baillargeon" <pb@artquest.net> wrote in message
news:38F5DD41.D42F7964@artquest.net...
>
> What I call meta-template is the ability to templatize the contraints
> put on template parameters. I envision this with the added ability to
> add "categorizing" template argument, where the programmer can specify
> the relation of categories (inheritance) and conversion. Example of
> simple categories: const, volatile, sorted. Then think about the
> relation between const and non-const and apply to other categories.
>
> So my question is: what do you think is the "next level" of generic
> programming? Do you see such an evolution as I described, or something
> else?
>
This is about as perfect of a lead-in for the additions I'm working on as I
could have hoped for, and seeing as how the only local library I've found
with a copy of D&E has checked it out to someone, I may as well explain it
here . . .
Here's what I see as the next level of generic programming. As it is, doing
anything serious with templates involves huge amounts of type-unsafety, and
trying to kludge starts getting really ugly. This is what I've been working
up as a possible solution - this and a few other minor additions that I've
been half-considering calling "MetaC++" and writing a compiler for. (The
name sucks, I know. But it's designed for metaprogramming, so . . .)
First, it started by being called compile-time inheritance, although I'm not
sure that applies anymore since that only covers part of it. If you prefer
webpages with nice graphics and explanations,
http://billingsms.org/~zorba/metac++/nother.htm is probably my best
description I've managed so far - for those who don't want to refer to the
webpage, I'll explain it here (again).
Note: This is not a full formalized explanation. I'm terrible at those. If
anyone has suggestions, questions, or wants to make this more formal (or has
suggestions for me doing it myself, I'm willing to work on this!), PLEASE,
talk to me!
So anyway . . .
A little background: For those who don't know, a lot of the speed of STL
(sorry, no hard facts to back this up, just feel and logic) comes from the
fact that it can be inlined. The calls directly to the container classes,
the iterator calls, all of it can be inlined because there aren't any
virtual functions. Since the interfaces to many of the STL classes are
near-identical (compare stl::list and stl::vector) they can be swapped out
by the programmer when he/she realizes that a different STL class fits the
usage pattern better.
Now, imagine for a second a function that requires "some STL class" to be
passed to it. You can hardcode the type . . .
int doSomething( std::vector *input );
but then if the programmer decides to switch to a list, this will break in a
rather ugly fashion. You could template it . . .
template < class containertype > int doSomething( containertype *input );
but you're not guarding against a programmer accidentally passing an int or
a long or misinterpreting the function requirements and passing an iterator.
Now, yes, it's going to be picked up pretty quickly by the compiler as an
error, but you're not going to get an "invalid argument type" error, at best
you're going to get a "unknown member function" error. And chances are, the
error is going to show up inside the template implementation, not the
function that mistakenly passed an iterator.
Now, those who have read the webpage are probably thinking "what is this guy
going on about, this is only somewhat related to what he was talking about
on the webpage" - that's because every time I try to explain this, I find
myself using a different example (oh well). But there's the basic idea - and
yes, this lets you overload template functions, something impossible at the
moment. I'm imagining something along the lines of . . .
template < derived_class< forward_iterator > containertype > void
someFunction( containertype *iterator ); // not very efficient
template < derived_class< bidirectional_iterator > containertype > void
someFunction( containertype *iterator ); // more efficient
template < derived_class< random_iterator > containertype > void
someFunction( containertype *iterator ); // extremely efficient
Where it would automatically choose the most efficient container (presumably
random_iterator is derived from bidirectional_iterator and
bidirectional_iterator is derived from forward_iterator). And since all this
is done at compiletime, it should all be inlineable.
The other thing I have in mind is a sort of extension to multiple
inheritance, where you could define a classtype only in terms of what
combination of classes it needs to be derived from. Now, you can (and, with
small numbers of classes, probably should) simply derive all the
combinations, then have each subclass derive from the appropriate "combo
class" - for instance, if we had A and B, we'd also have AB. A, B, and C
would yield AB, AC, BC, and ABC. But it starts getting harder to manage with
more classes.
Now, imagine if you had a set of default "class behaviors". For example, you
could derive a class from "searchable_in_logarithmic_time" or
"searchable_in_constant_time" (yes, you'd want better class names than
those), with searchable_in_constant_time derived from
searchable_in_logarithmic_time. Then if you had a function that needed a
particular behavior, you could just specify the required combo class. I'm
imagining something along the lines of . . .
void someFunction( multiple_requirements< drawable, serializable > *item );
which would be quite handy for, say, a transparent remote graphical
terminal. And this would merge quite nicely with compile-time inheritance,
albeit generating some absurdly long function declarations.
Anyone still reading this? . . . if you are, I'd love feedback! I'd love it
even better if I got suggestions on how to improve these ideas or explain
them better, I made these single-handedly and I'm well aware that I'm not
the most articulate person in the world . . .
-Zorba
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: =?ISO-8859-1?Q?J=F6rg?= Barfurth <joerg.barfurth@germany.sun.com>
Date: 2000/04/15 Raw View
Am 14.04.00, 07:33:05, schrieb Pierre Baillargeon <pb@artquest.net> zum
Thema Re: signatures or interfaces in C++:
> Christopher Eltschka wrote:
> > I don't think that would work too well:
> >
> > void f(sorted vector<i>);
> > void f(vector<i>);
> >
> > void foo()
> > {
> > std::vector<int> i;
> > // fill i
> >
> > if (I_want_it_sorted)
> > sort(i);
> > else
> > scramble(i);
> >
> > // is i now sorted?
> > f(i); // which f should be called?
> > }
> >
> I changed my original example from "a function taking a reference to a
> normal vector and returning a reference to a sorted vector" to the I
> wrote and that you show, not realizing the fundamental difference. Also,
> I changed some semantics in the process.
> My original idea, which I'll revert to now, is to treat the user-defined
> qualifiers just like "const". So that your example would turn into:
> qualifier sorted;
> template <class T> sorted std::vector<T> & sort ( std::vector<T> & );
> template <class T> std::vector<T> & scramble ( std::vector<T> & );
BTW: How could the compiler help enforce the intented semantics in the
implementation of sort ?
> void f(sorted vector<i> &); // 1.
> void f(vector<i> &); // 2.
> // Note: f 2. could take sorted or non-sorted vectors just as if
> // the "sorted" qualifier was the "const" qualifier,
> // but the overload of f 1. prevents this.
What is different from 'const' is, that with const (or volatile)
qualifiers can be implicitly added (instead of removed). This is because
adding a qualifier always adds usage restrictions.
> void foo()
> {
> std::vector<int> i;
> // fill i
> std::vector<int> * normal = 0;
> sorted std::vector<int> * sorted = 0;
> if (I_want_it_sorted)
> sorted = & sort(i);
> else
> normal = & scramble(i);
> // is i now sorted? *NO*
> f(i); // f 2. is called.
> if (normal)
> f(*normal); // f 2. is called.
> if (sorted)
> f(*sorted); // f 1. is called.
> }
Another difference: const/volatile don't express an attribute of the
object referred to when used with references (or pointers). They just
express constraints on accessing the object through this access path. A
object reffered to through a T const volatile & need not be const or
volatile. Modifying your example:
void foo()
{
std::vector<int> i;
// fill i
sorted std::vector<int>& sorted_i = sort(i);
// I assume sorted_i is supposed to refer to the object i
scramble(i);
f(sorted_i); // but i isn't sorted any more
}
> So once again, changing one's idea at the last moment while writing a
> post is a *bad* idea!
Maybe you could summarize your idea in its present form again.
Extending the static type-checking of C++ to support semantic,
user-defined concepts is a nice idea, but the problem lies in having the
compiler enforce semantics it doesn't know.
-- J rg
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/04/06 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
> Hyman Rosen schrieb:
> > Not being able to inherit implementations in Java is a nuisance.
> not necessarily: the reason for usage of interfaces is that you want to
> have the same interface for otherwise different types and thus you
> usually have different implementations.
But for those cases where a particular implementation is suitable
for different types, Java loses - implementations must be recoded
in classes instead of being inherited. This is especially the case
for the common Java idiom of Adapter classes which provide null
implementations for interfaces.
======================================= MODERATOR'S COMMENT:
Please re-direct any responses which do not relate to Standard
C++ to e-mail
or to a newsgroup better suited to debating the strengths and weaknesses
of Java.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 2000/04/09 Raw View
>>>>> "fjh" == Fergus Henderson <fjh@cs.mu.OZ.AU> writes:
fjh> Signatures provide several things that templates don't:
[...]
OK, you convinced me that this is the case.
Do you believe however that it would be worth adding signatures to
standard C++ instead of fixing templates and developing work-around
practices (e.g. heterogeneous collections through collections of smart
pointers to base classes)?
I seriously doubt it.
--
Marc Girod P.O. Box 320 Voice: +358-9-511 23746
Nokia Networks 00045 NOKIA Group Mobile: +358-40-569 7954
Hiomo 5/1 Finland Fax: +358-9-511 23580
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/04/09 Raw View
"Robert O'Dowd" <nospam@nonexistant.com> writes:
|> So, from a C++ perspective, there is no real need to distinguish
|> between classes and interfaces --- an interface is a class with
|> particular attributes. From a Java perspective, there is a
|> need to make that distinction, arising from a class model that
|> disallows multiple inheritence of implementation.
One could argue whether the distinction brings any benefits to a Java
programmer. One could say that Java implements a very limited
inheritance model, with only two special cases supported, and that two
key words are there to help the compiler distinguish between the two
special cases (which generally will require different implementations).
--
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/04/09 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
|> Hyman Rosen schrieb:
|> > Robert Klemme <robert.klemme@myview.de> writes:
|> > > i do know that i can use multiple inheritance for the same
|> > > purpose, but for some reasons (you might as well call some of the
|> > > aesthetic) i do find interfaces in java the better concept.
|> > Not being able to inherit implementations in Java is a nuisance.
|> not necessarily: the reason for usage of interfaces is that you want to
|> have the same interface for otherwise different types and thus you
|> usually have different implementations.
Independantly of the mixin technology, the restrictions have shown
themselves very binding in case of evolution. On need only to look at
the Swing classes to see the problem: JComponent should logically
inherit from Component, with a JContainer inheriting from both
JComponent and Container. Which, of course, Java doesn't allow, so we
have the anomolous situation of being able to add Components to a
JButton (which can cause some very peculiar display).
Of course, this particular situation is only due to a problem of
backwards compatibility -- in an ideal world, they'd have designed the
GUI library right the first time, and the hierarchy of the AWT classes
would be the only one. But the problem is general anytime you try and
fit existing code into a new structure. About the only time your safe
from it is when you write everything from scratch yourself -- a luxury
that not many people can afford these days.
--
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/04/10 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
|> can anybody with some insight into the standardization process give an
|> estimate whether a feature similar to java's interface is likely to make
|> it into c++?
It's called an abstract class, it's already part of C++, and it does
everything Java's interface does, and more. (For example, you can
implemented enforced pre- and post-conditions, which is not possible in
a Java interface.)
|> i know there is an implementation of this in gnu's g++
|> though i do neither know how robust this is nor whether this is still
|> maintained. (they call it signature btw.)
I'm not too familiar with signatures, but I don't think they have
anything to do with Java-like interfaces.
--
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/04/10 Raw View
Marc Girod <girod@stybba.ntc.nokia.com> writes:
>>>>>> "fjh" == Fergus Henderson <fjh@cs.mu.OZ.AU> writes:
>
>fjh> Signatures provide several things that templates don't:
>[...]
>
>OK, you convinced me that this is the case.
>Do you believe however that it would be worth adding signatures to
>standard C++ instead of fixing templates and developing work-around
>practices (e.g. heterogeneous collections through collections of smart
>pointers to base classes)?
No, the damage is already done; C++ is already complex enough as is,
and the costs from the additional complexity of adding signatures
would probably not be worth the benefit now.
But the designers of future languages would do well to study the support
for generics and signatures in Sather, which is IMHO quite a bit nicer
than C++ templates.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: kanze@gabi-soft.de
Date: 2000/04/11 Raw View
Pierre Baillargeon <pb@artquest.net> writes:
|> What I find interesting in this is the fact that we are now, relative to
|> templates, in a situation much like the one of K&R C, relative to
|> functions.
This is only partially true. If you make a mistake in using the
template interface, you will normally get a compile time error. The
error text will probably be misleading, but at least, the results won't
be undefined runtime behavior.
Note too that many languages (Lisp, Smalltalk, etc.) have done quite
well without function prototypes. Again, by verifying and generating an
error when the illegal usage occurs (at run-time, in these cases). I
greatly prefer the compile time checking of C++ and Java, but that
doesn't mean that the other solution is necessarily invalid.
--
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/04/12 Raw View
kanze@gabi-soft.de writes:
>Pierre Baillargeon <pb@artquest.net> writes:
>
>|> What I find interesting in this is the fact that we are now, relative to
>|> templates, in a situation much like the one of K&R C, relative to
>|> functions.
>
>This is only partially true. If you make a mistake in using the
>template interface, you will normally get a compile time error. The
>error text will probably be misleading, but at least, the results won't
>be undefined runtime behavior.
If you make a mistake in using the standard library templates, then
the result can indeed be undefined runtime behaviour.
See 17.4.3.6 [lib.res.on.functions].
Also, if you make a mistake in using a template interface, but
you do so in another template, then the error will generally not
be detected at compile time, but rather only at link time.
Furthermore, if the offending template is not instantiated,
then the error will not be detected at all. Of course,
if the offending template is not instantiated, then the problem
won't cause an runtime errors either, but the delay in the
detection of such errors can still be costly -- as is shown by
the many inconsistencies in the template requirements of the
standard library itself.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/04/02 Raw View
Marc Girod <girod@stybba.ntc.nokia.com> writes:
>>>>>> "fjh" == Fergus Henderson <fjh@cs.mu.OZ.AU> writes:
>
>fjh> In particular, this means you can do the equivalent of adding a
>fjh> new base class to some existing class without modifying the
>fjh> source code for that existing class. This gives you additional
>fjh> flexibility that neither Java interfaces nor C++ abstract base
>fjh> classes provide.
>
>But it duplicates something templates provide already.
Signatures provide several things that templates don't:
- heterogeneous collections (this is a very big difference!)
- documentation of the requirements on parameters
- compile-time checking that those requirements are met (templates
provide only link-time checking, and check only the subset of the
documented requirements that this particular instance uses)
With regard to the third point, the C++ standard contains a number of
errors and contradictions in its description of the standard template library,
which could easily have been detected statically if it had been using
signatures rather than templates.
There's also a significant difference in the performance model between
signatures and templates; in the general case, signatures must use
code sharing, while in the general case, templates must use template
instantiation. Of course, for each feature, optimizing implementations can
sometimes generate code using the opposite model, but doing so is more
complicated, and only applies in restricted circumstances. For example,
specializing code using signatures so that a separate copy is used for each
type cannot be done if that code is using heterogenous collections.
Conversely, doing code-space optimizations on templates to introduce
code-sharing cannot be done for cases where the programmer has used template
specialization or where the sequences of implicit conversions etc. that are
involved are different for each type.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: 2000/04/02 Raw View
Pierre Baillargeon <pb@artquest.net> writes:
| Gabriel Dos Reis wrote:
| >
| >
| > which in C++ might be expressed as:
| >
| > template<typename X, typename T>
| > concept input_iterator {
| > X::X(const X&);
| > X& X::operator=(const X&);
| > bool operator==(const X&, const X&);
| > bool operator!=(const X&, const X&);
| > T* X::operator->();
| > T& X::operator*();
| > X& operator++(X&);
| > X operator++(X&, int);
| > };
| >
|
| A few weeks back, Bjarne Stroustrup was interviewed on Slashdot, and I
| asked a question about this subject. Unfortunately, my question did not
| make it to the interview. So is it planned to add such a feature to g++
| in the future?
I'm not aware of any plan to implement such a feature in g++.
I planned to experiment with SML-like signature in g++ once the parser
is rewritten, but that is an enterily different issue.
| What I find interesting in this is the fact that we are now, relative to
| templates, in a situation much like the one of K&R C, relative to
| functions. What I mean is that functions used to be non-prototyped, much
| like templates are not prototyped relative to their parameters. It was
| the implementation that defined the function arguments in K&R C, much
| like it is the template implementation that defines the requirements put
| on parameters.
|
| Adding function prototypes added type-safety. More importantly, later,
| it also allowed function to be overloaded and templated. Without
| prototypes, you can't tell the compiler that it can choose among a set
| of functions instead of a single one. So overloading and template are
| not possible.
|
| So, I wonder if adding "prototypes" to template would yield the same
| improvements.
I guess only experiments could tell its practical usefulness. But my
personal experience is that we need a language construct to improve
error dectection and error message in heavy template based program.
| ... That is, the ability to more easily provide alternative
| implementations depending on the nature of the parameters.
|
| Currently, we must use partial specialization, traits, or other
| mechanism. Am I erring, or is this analysis somewhat on target?
I think your analysis is right. Sometimes I find traits to be really
painful.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/04/06 Raw View
Hyman Rosen schrieb:
>
> Robert Klemme <robert.klemme@myview.de> writes:
> > i do know that i can use multiple inheritance for the same
> > purpose, but for some reasons (you might as well call some of the
> > aesthetic) i do find interfaces in java the better concept.
>
> Not being able to inherit implementations in Java is a nuisance.
not necessarily: the reason for usage of interfaces is that you want to
have the same interface for otherwise different types and thus you
usually have different implementations.
robert
--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra e 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/03/31 Raw View
In article <38E33C57.AE707EBA@myview.de>, Robert Klemme
<robert.klemme@myview.de> writes
>i think there is a significant distinction between interfaces and
>multiple (virtual) inheritance.
If it looks like a bird, sings like a bird and flies like a bird it
might as well be a bird even if its really a bat:)
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/03/31 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
> > Signatures are not interfaces.
> hm. can you please explain what the exact difference is?
If I recall correctly, any class which implemented the members of a
signature could be passed where a signature of that type was needed.
With Java interfaces, a class must explicitly implement the interface
in order to be used where the interface is required. Simply having the
same members is insufficient.
> > C++ already (almost) has interfaces.
>
> i would oppose to that. c++ may have a feature which can be used for a
> similar purpose (i am talking of multiple inheritance of course) but
> saying that c++ has interfaces is wrong as far as i'm concerned.
You may believe whatever you like. You are incorrect, though.
> this is all multiple inheritance stuff and no interfaces!
> i think there is a significant distinction between interfaces and
> multiple (virtual) inheritance. those are different concepts. multiple
> inheritance is fine as long as there is no state and just operations
> involved. but when it comes to state (i.e. member data) multiple
> inheritance can be a real pita - especially but not only for compiler
> constructors.
I demonstrated the mapping between Java interfaces and C++. In no case
did my examples have multiple inheritance of objects with state, so I
don't see the relevance of complaining about such inheritance. You may
choose to believe that Java's multiple inheritance of interfaces is
somehow entirely different from C++'s multiple inheritance, but that
does not make you correct.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Robert O'Dowd" <nospam@nonexistant.com>
Date: 2000/03/31 Raw View
Hyman Rosen wrote:
>
> Robert Klemme <robert.klemme@myview.de> writes:
> > > Signatures are not interfaces.
> > hm. can you please explain what the exact difference is?
>
> If I recall correctly, any class which implemented the members of a
> signature could be passed where a signature of that type was needed.
> With Java interfaces, a class must explicitly implement the interface
> in order to be used where the interface is required. Simply having the
> same members is insufficient.
>
> > > C++ already (almost) has interfaces.
> >
> > i would oppose to that. c++ may have a feature which can be used for a
> > similar purpose (i am talking of multiple inheritance of course) but
> > saying that c++ has interfaces is wrong as far as i'm concerned.
>
> You may believe whatever you like. You are incorrect, though.
Java supports explicit keywords (interface and implements) that serve to
distinguish Java interfaces from Java classes --- a difference which
fundamentally would give nothing to C++, but is slightly more crucial
for Java because Java does not support a more general form of
multiple inheritence.
There are some subtle differences between multiple inheritence of Java
interfaces and the C++ equivalent (multiple inheritence from base
classes
with pure virtual member functions and no data members). For
example, a Java class that declares it implements a given interface
*must* provide implementations for all member functions declared
in that interface. The inheritence model of C++ is more complete
(inheritence of implementation as well as interface). This allows
alternate mechanisms for a C++ programmer to implement an interface,
like mixin classes.
So, from a C++ perspective, there is no real need to distinguish
between classes and interfaces --- an interface is a class with
particular attributes. From a Java perspective, there is a
need to make that distinction, arising from a class model that
disallows multiple inheritence of implementation.
>
> > this is all multiple inheritance stuff and no interfaces!
> > i think there is a significant distinction between interfaces and
> > multiple (virtual) inheritance. those are different concepts. multiple
> > inheritance is fine as long as there is no state and just operations
> > involved. but when it comes to state (i.e. member data) multiple
> > inheritance can be a real pita - especially but not only for compiler
> > constructors.
>
> I demonstrated the mapping between Java interfaces and C++. In no case
> did my examples have multiple inheritance of objects with state, so I
> don't see the relevance of complaining about such inheritance. You may
> choose to believe that Java's multiple inheritance of interfaces is
> somehow entirely different from C++'s multiple inheritance, but that
> does not make you correct.
>
I suspect the point being made is that your approach ignores a
difference between classes and interfaces that is rather fundamental
to Java. Functionally, I agree, it makes little difference.
However, your approach is actually more general than the Java
approach, in that you have removed some constraints imposed by
the Java language. I suspect the removal of those constraints
is one of Robert Klemme's objections. That is a valid,although
picky, objection. His other objection is presumably lack of
keywords like "interface" and "implements" (which are associated
with the constraints imposed by Java). That can't be fully
addressed without extending the C++ language in ways that
wouldn't really add a lot to C++.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: 2000/04/01 Raw View
Hyman Rosen <hymie@prolifics.com> writes:
>Robert Klemme <robert.klemme@myview.de> writes:
>> > Signatures are not interfaces.
>> hm. can you please explain what the exact difference is?
>
>If I recall correctly, any class which implemented the members of a
>signature could be passed where a signature of that type was needed.
In particular, this means you can do the equivalent of adding a new base class
to some existing class without modifying the source code for that existing
class. This gives you additional flexibility that neither Java interfaces
nor C++ abstract base classes provide.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/04/01 Raw View
Hyman Rosen schrieb:
>
> Robert Klemme <robert.klemme@myview.de> writes:
> > > Signatures are not interfaces.
> > hm. can you please explain what the exact difference is?
>
> If I recall correctly, any class which implemented the members of a
> signature could be passed where a signature of that type was needed.
> With Java interfaces, a class must explicitly implement the interface
> in order to be used where the interface is required. Simply having the
> same members is insufficient.
this is correct. apart from that, the similarity remains that i declare
the interface of a class with a g++ signature as well as with a java
interface and i'm bound to method signatures - not state involved.
> > i would oppose to that. c++ may have a feature which can be used for a
> > similar purpose (i am talking of multiple inheritance of course) but
> > saying that c++ has interfaces is wrong as far as i'm concerned.
>
> You may believe whatever you like. You are incorrect, though.
thank's for leaving me at least my religious freedom. :-))
> > this is all multiple inheritance stuff and no interfaces!
> > i think there is a significant distinction between interfaces and
> > multiple (virtual) inheritance. those are different concepts. multiple
> > inheritance is fine as long as there is no state and just operations
> > involved. but when it comes to state (i.e. member data) multiple
> > inheritance can be a real pita - especially but not only for compiler
> > constructors.
>
> I demonstrated the mapping between Java interfaces and C++. In no case
> did my examples have multiple inheritance of objects with state,
this is all true, but you can have state with c++ multiple inheritance
which you cannot with interfaces.
> so I
> don't see the relevance of complaining about such inheritance. You may
> choose to believe that Java's multiple inheritance of interfaces is
> somehow entirely different from C++'s multiple inheritance, but that
> does not make you correct.
as the other robert stated, this might be picky. i'm sorry that i'm
used to trying to be as exact as possible and try to distinguish birds
from bats - which is easy in this case, since the behaviour of the two
concepts is by far not similar. (some might even call this
pedantry...) i do know that i can use multiple inheritance for the same
purpose, but for some reasons (you might as well call some of the
aesthetic) i do find interfaces in java the better concept.
regards
robert
--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra e 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Marc Girod <girod@stybba.ntc.nokia.com>
Date: 2000/04/01 Raw View
>>>>> "fjh" == Fergus Henderson <fjh@cs.mu.OZ.AU> writes:
fjh> In particular, this means you can do the equivalent of adding a
fjh> new base class to some existing class without modifying the
fjh> source code for that existing class. This gives you additional
fjh> flexibility that neither Java interfaces nor C++ abstract base
fjh> classes provide.
But it duplicates something templates provide already.
Signatures are an implementation of genericity, not of classification:
they express an interface as a sum of features, instead of as a
position in a lattice.
--
Marc Girod P.O. Box 320 Voice: +358-9-511 23746
Nokia Networks 00045 NOKIA Group Mobile: +358-40-569 7954
Hiomo 5/1 Finland Fax: +358-9-511 23580
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/04/01 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
> i do know that i can use multiple inheritance for the same
> purpose, but for some reasons (you might as well call some of the
> aesthetic) i do find interfaces in java the better concept.
Not being able to inherit implementations in Java is a nuisance.
C++:
====
struct I1 { virtual void foo() = 0; virtual void bar() = 0; };
struct I1Adapter : virtual I1 { void foo() { } void bar() { } };
struct I2 { virtual void able() = 0; virtual void baker() = 0; };
struct I2Adapter : virtual I2 { void able() { } void baker() { } };
struct my_class : virtual I1Adapter, virtual I2Adapter
{
void foo() { interesting_foo_stuff(); }
void baker() { interesting_baker_stuff(); }
};
Java:
=====
interface I1 { void foo; void bar; }
class I1Adapter implements I1 { public void foo() { } public void bar() { } }
interface I2 { void able(); void baker(); }
class I2Adapter implements I2 { public void able() { } public void baker() { } }
class my_class implements I1, I2 extends I1Adapter
{
public void foo() { interesting_foo_stuff(); }
public void baker() { interesting_baker_stuff(); }
public void able() { } // useless repetition
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/03/30 Raw View
hi all,
can anybody with some insight into the standardization process give an
estimate whether a feature similar to java's interface is likely to make
it into c++? i know there is an implementation of this in gnu's g++
though i do neither know how robust this is nor whether this is still
maintained. (they call it signature btw.)
any information is appreciated. thank you!
regards
robert
--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra e 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/03/30 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
> can anybody with some insight into the standardization process give an
> estimate whether a feature similar to java's interface is likely to make
> it into c++? i know there is an implementation of this in gnu's g++
> though i do neither know how robust this is nor whether this is still
> maintained. (they call it signature btw.)
Signatures are not interfaces. The feature is no longer maintained.
C++ already (almost) has interfaces.
If in Java you say 'interface a { int f(); }'
then in C++ you say 'struct a { virtual int f() = 0; };'.
If in Java you say 'interface c extends a, b {}'
then in C++ you say 'struct c : virtual a, virtual b { };'.
If in Java you say 'class b implements a { public int f() { return 0; } }'
then in C++ you say 'struct b : virtual a { int f() { return 0; } };'.
Here's the only difference:
In Java, you say
interface a { int f(); } class b { public int f() { return 0; }
class ab implements a extends b { }
In C++, you must then forward:
struct a { virtual int f() = 0; };
struct b { int f() { return 0; } };
struct ab : virtual a, b { int f() { return b::f(); } };
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: 2000/03/30 Raw View
Robert Klemme <robert.klemme@myview.de> writes:
| hi all,
|
| can anybody with some insight into the standardization process give an
| estimate whether a feature similar to java's interface is likely to make
| it into c++? i know there is an implementation of this in gnu's g++
| though i do neither know how robust this is nor whether this is still
| maintained. (they call it signature btw.)
That extension is no longer supported and will completely disappear
from the next release of GCC.
However, I think a signature a la SML will be proven very handful for
requirements checking.
Consider
signature INPUT_ITERATOR =
sig
type X;
type T;
val copy : X -> X;
val assign : X -> X;
val == : X * X -> bool;
val != : X * X -> bool;
val select : X * 'a -> 'a;
val dereference : X -> T;
val pre_increment : X -> X;
val post_increment : X -> X;
end;
which in C++ might be expressed as:
template<typename X, typename T>
concept input_iterator {
X::X(const X&);
X& X::operator=(const X&);
bool operator==(const X&, const X&);
bool operator!=(const X&, const X&);
T* X::operator->();
T& X::operator*();
X& operator++(X&);
X operator++(X&, int);
};
The std::vector template constructor taking a pair of input iterator
(yes, the one with the do-the-right-thing infamous hack) might be
expressed as:
template<typename T, typename Allocator>
class vector {
// ...
template<typename InputIterator : input_iterator>
vector(InputIterator, InputIterator);
// ...
};
so that when I mistakenly write something along the lines:
#include <vector>
struct X { X(int) {} };
int main()
{
std::vector<int> array(X(1901), X(2000)); // oops X is not
// integral nor iterator
}
I can get an understable diagnostic.
Naturally, that is not a full proposal. It merely points out
possibilities where constraints on template (or something more general
like SML-like signature) might be handful.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/03/31 Raw View
hi,
very interesting although i was more thinking along the lines of runtime
polymorphism. i know that in java there's more to this than just
interfaces but interfaces could make multiple inheritance superfluous.
(i know this is not going to be thrown out of c++ for compatibility
reasons. but the language could be augmented by this feature - this
would do no harm.)
regards
robert
Gabriel Dos Reis schrieb:
>
> Robert Klemme <robert.klemme@myview.de> writes:
>
> | hi all,
> |
> | can anybody with some insight into the standardization process give an
> | estimate whether a feature similar to java's interface is likely to make
> | it into c++? i know there is an implementation of this in gnu's g++
> | though i do neither know how robust this is nor whether this is still
> | maintained. (they call it signature btw.)
>
> That extension is no longer supported and will completely disappear
> from the next release of GCC.
>
> However, I think a signature a la SML will be proven very handful for
> requirements checking.
> [...]
--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra e 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pierre Baillargeon <pb@artquest.net>
Date: 2000/03/31 Raw View
Gabriel Dos Reis wrote:
>
>
> which in C++ might be expressed as:
>
> template<typename X, typename T>
> concept input_iterator {
> X::X(const X&);
> X& X::operator=(const X&);
> bool operator==(const X&, const X&);
> bool operator!=(const X&, const X&);
> T* X::operator->();
> T& X::operator*();
> X& operator++(X&);
> X operator++(X&, int);
> };
>
A few weeks back, Bjarne Stroustrup was interviewed on Slashdot, and I
asked a question about this subject. Unfortunately, my question did not
make it to the interview. So is it planned to add such a feature to g++
in the future?
What I find interesting in this is the fact that we are now, relative to
templates, in a situation much like the one of K&R C, relative to
functions. What I mean is that functions used to be non-prototyped, much
like templates are not prototyped relative to their parameters. It was
the implementation that defined the function arguments in K&R C, much
like it is the template implementation that defines the requirements put
on parameters.
Adding function prototypes added type-safety. More importantly, later,
it also allowed function to be overloaded and templated. Without
prototypes, you can't tell the compiler that it can choose among a set
of functions instead of a single one. So overloading and template are
not possible.
So, I wonder if adding "prototypes" to template would yield the same
improvements. That is, the ability to more easily provide alternative
implementations depending on the nature of the parameters.
Currently, we must use partial specialization, traits, or other
mechanism. Am I erring, or is this analysis somewhat on target?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Klemme <robert.klemme@myview.de>
Date: 2000/03/31 Raw View
Hyman Rosen schrieb:
>
> Robert Klemme <robert.klemme@myview.de> writes:
> > can anybody with some insight into the standardization process give an
> > estimate whether a feature similar to java's interface is likely to make
> > it into c++? i know there is an implementation of this in gnu's g++
> > though i do neither know how robust this is nor whether this is still
> > maintained. (they call it signature btw.)
>
> Signatures are not interfaces.
hm. can you please explain what the exact difference is?
> The feature is no longer maintained.
> C++ already (almost) has interfaces.
i would oppose to that. c++ may have a feature which can be used for a
similar purpose (i am talking of multiple inheritance of course) but
saying that c++ has interfaces is wrong as far as i'm concerned.
> If in Java you say 'interface a { int f(); }'
> then in C++ you say 'struct a { virtual int f() = 0; };'.
>
> If in Java you say 'interface c extends a, b {}'
> then in C++ you say 'struct c : virtual a, virtual b { };'.
>
> If in Java you say 'class b implements a { public int f() { return 0; } }'
> then in C++ you say 'struct b : virtual a { int f() { return 0; } };'.
this is all multiple inheritance stuff and no interfaces!
> Here's the only difference:
>
> In Java, you say
>
> interface a { int f(); } class b { public int f() { return 0; }
> class ab implements a extends b { }
>
> In C++, you must then forward:
>
> struct a { virtual int f() = 0; };
> struct b { int f() { return 0; } };
> struct ab : virtual a, b { int f() { return b::f(); } };
i think there is a significant distinction between interfaces and
multiple (virtual) inheritance. those are different concepts. multiple
inheritance is fine as long as there is no state and just operations
involved. but when it comes to state (i.e. member data) multiple
inheritance can be a real pita - especially but not only for compiler
constructors.
regards
robert
--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestra e 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert.klemme@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]