Re: Are homonymous non-template and template classes incompatible?
Barry Kelly wrote:
James Kanze <kanze.james@neuf.fr> wrote:
Barry Kelly wrote:
> f<int>();
> f<int,int>();
That's not function overloading
I'll beg to differ -
The C++ standard disagrees with you:-).
as a pragmatic reader of the source code, I see that the
compiler is deciding what function to call based on the kind
and number of arguments, and that's a practical enough
definition of overloading for me, a humble codesmith. The
arguments may be passed to a template, but they are arguments
all the same. If it quacks like a duck, etc.
There's a significant difference. In this case, you are
explicitly telling the compiler which function to call. It may
be overloading, in some way. (It is certainly overloading of
the function name.) But there isn't any "overload resolution"
on the part of the compiler.
> A symbol may have one semantic meaning, but that doesn't
> rule out overloaded identifiers as a useful language
> construct.
Within certain, very constrained limits. It's also a very
powerful tool for obfuscation.
One of the most essential limits is that the overloads all
concern the same sort of things: in C++, for example, you
can overload functions, but you cannot overload a function
with a variable. I could more or less see some sort of
reasoning to accept overloading templates ... say rather
than partial specialization, allowing two class templates
with the same name to have a different number of parameters.
But overloading templates and non-templates. That seems
carrying things way too far.
Another way of looking at it is that non-templated functions
and types are simply templates with no parameters. It's a
matter of perspective.
OK. I can sort of buy that. It would make sense if (and only
if) we also allowed overloading of class templates. That's not
currently the case, and given the rest of the language
definition, I'm not sure it would be trivial to do so.
I'm also not convinced that it is worth it. (And of course, I'm
very worried that it would be abused. Operator overloaded has
often been abused, and the one example so far of where it might
be used also counts as abuse in my book. A base class is not a
derived class, and giving them the same name rates at about the
same level as overloading operator+ to mean subtraction.)
>>> My opinion is that if the compiler parser was able to cope
>>> with the syntax, then the generated code would be supported by
>>> any linker because of the different mangling of non-template
>>> and template homonymous classes.
>> And if pigs had wings, they could fly. How on earth could
>> the compiler parser possibly cope with this? For that
>> matter, how on earth could a human reader cope with it?
> It's not difficult when you get used to it. It's a common
> mistake in the C# world for people to confuse a generic type
> T<P> with T, when the two are completely different things with
> no relationship - just like the two functions above are two
> different things with no relationship.
The problem is that you then have ambiguities in
interpreting the <.
You'll have to show me an actual ambiguity that doesn't
already exist for functions and function templates for me to
believe you!
You already have them. What does something like f<a>(b) mean?
You're proposing to add to them. What I (and a lot of other
people) would like to see is a proposal to reduce them; they
cause problems for both human readers and the compiler. We can
invent disambiguating rules for the compiler; the compiler will
apply them rigorously and without fault. We can't do the same
for human readers, because human readers are not always 100%
rigorous.
Leaving functions aside: C already has a problem with types
(i.e. typedefs) causing ambiguities in LALR(1) and LL(1)
grammars. A common solution is to recognize types in the lexer
by looking up identifiers in the symbol table. C++ template
names face a similar problem, and can use the same solution.
If that solution is used, and one has a type or template name
followed by a '<', the parser can see that it can't be a valid
expression, so there is no ambiguity with the less than
operator.
Nobody is saying that we cannot find a set of rules to remove
the ambiguity. C++ already has a certain number of ambiguities,
resolved by special rules. (Consider the most vexing parse
issue, for example.) Just because we've made the mistake
several times in the past, however, doesn't mean that we should
go on making it.
However, I will say that I think C++ has blurred the
difference between templates and non-templates with its
inference capabilities, and that this blurring would make an
introduction of this feature (overloading templated classes
with a non-templated class name) into C++ unwise.
I'm not sure what you mean by "its inference capabilities". C++
has two very separate mechanisms which come into play in a
function call: template type induction, and operator overload
resolution. From a formal point of view, they are completely
separate: type induction decides which functions to
instantiate, if any; the instantiated functions are added to the
overload set, and overload resolution then chooses the "best"
match from this set.
It's a complex, and IMHO rather confusing process. Given the
history and the expectations, it's hard to see how it could have
been any simpler. But people regularly get confused by it.
Anything which adds to the confusion, or causes it to appear in
new contexts, should be avoided. We've already got more
confusion than we want.
> It's then natural to name the common non-generic base
> class as the generic's name, without the type
> parameters.
It sounds like a recepe for obfuscation to me. What's wrong
with AbstractMyTemplateClass, or MyTemplateClassBase? Works
for me.
If one changes one's perspective on identifiers denoting
non-templated functions and types as denoting templates taking
no parameters, then the problems disappear. Since C++
templates can be reasoned about as functions over the parse
tree in the compiler, non-templates become factors taking no
parameters in the mini expression language of C++ templates. I
hope I'm making sense!
You are, and I can follow your reasoning very well. But I still
disagree with regards to the benefits (which I don't yet see) as
opposed to the cost -- one more place where we have to try to
figure out how the compiler is going to interpret what we've
written.
One always has the problem of ensuring some level of semantic
equivalence whenever an identifier is overloaded. The
usefulness of the "non-generic type as a base type" idiom is
that it has *genuine* semantic equivalence properties, because
of polymorphism / Liskov substitution etc. It's worked well
for me and others, albeit not (obviously) in C++. Again, with
the way type inference works in C++, I think it would be a bad
idea to consider adding it. C++ is already complicated enough
in that area, IMHO.
Why not use a different name? One can ask the same question
about overloaded functions. Using the same name for the same
concept has a certain elegance, I suppose. If I have some
Foo<Bar> and some Foo<Baz> and other kinds of Foo<>, and I
need to do something requiring dynamic dispatch with all kinds
of Foo, why introduce a new name?
Because a base class isn't conceptually the same thing as a
derived class. They are, in fact, radically different -- about
as different as addition and subtraction, or as adding or
removing an element from a collection.
--
James Kanze GABI Software
Conseils en informatique orient?e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S?mard, 78210 St.-Cyr-l'?cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]