Jeffrey Schwab said:
The rough equivalent would be:
void do_something(list<Auditable*> events);
~$ cat main.cpp
#include <list>
using namespace std;
class Auditable { };
class Event1 : public Auditable { };
class Event2 : public Auditable { };
void do_something(list<Auditable *> events);
int main(int argc, char *argv)
{
list<Event1 *> e;
do_something(e);
return 0;
}
~$ g++ main.cpp
main.cpp: In function `int main(int, char*)':
main.cpp:13: error: conversion from `std::list<Event1*, std::allocator
<Event1*>>' to non-scalar type `std::list<Auditable*, std::allocator
This can be done in pretty much the same way as the do_something()
example, but it's typically not necessary.
Since the do_something() example didn't work, I suppose that doesn't
bode well for other things done in pretty much the same way.
If you just use the
necessary features of T in the body of your template, the compiler will
choose the right code for you automatically.
Yes, absolutely; which makes templates a great mechanism for
abbreviating and abstracting code, but not for more powerful type
checking.
Some checks are done before the expansion (unlike macros), but others
are done afterward. That part actually gets complicated.
You seem to have assumed a rather narrow definition of "macro". That
explains some of the confusion here. I did not mean to imply such a
narrow definition of a macro. Nevertheless, no checks that are
interesting in terms of the expressive power of the type system are
performed prior to macro expansion. Templates allow all sorts of
interesting evaluation to occur within the compiler (an entire Turing
complete language, in fact), but very little additional expressive
power.
Not sure I understand the word "subsumption" in this context.
It means that given:
class Dog { public: void run(); };
class Thread { public: void run(); };
and:
class Scheduler<T> { ... t.run(); ... };
it is just as valid to the language to declare Scheduler<Dog> as
Scheduler<Thread>, and there's no mechanism in the language to prevent
that from occurring. The example becomes more relevant when you
consider operator overloading, but I think it's easier to understand
with plain methods. This is just an example of the minimal thing that
would be prevented by an extension to the type system to handle
reasonable constraints about parameterized types. It's not the only
possible benefit of such an exercise. If you'd like to point to others,
I'm all ears.
I'm sorry for offending you. But you really don't seem to know what
you're talking about.
Feel free to correct me if I'm wrong about something. So far in this
thread, I don't believe I have been wrong about anything. So far, it
appears that asking whether Java generics or C++ templates are more
powerful is much akin to asking whether the President of the United
States is more powerful than a locomotive. Depending on whose
definition of "powerful" you adopt for evaluating the question, you come
up with different answers. It further appears that you responded to my
message without taking the time to understand the sense in which
generics in Java are powerful. Understandably, then, you reached an
incorrect conclusion.