Topic: Observations on templates
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/12 Raw View
solution@gate.net (Ken Walter) writes:
>I always thought the following was interesting:
>
>template <class T, class S> T cast_d( S s) { return dynamic_cast<T>s; }
That won't quite do what you want, because you are using
pass-by-value. That will result in copying, giving `cast_d' quite
different semantics to `dynamic_cast'. You should use
pass-by-reference instead. You then need to overload the function to
allow all possible sorts of references:
template <class T, class S> T cast_d(S &s) { return dynamic_cast<T>s; }
template <class T, class S> T cast_d(const S &s) { return dynamic_cast<T>s; }
template <class T, class S> T cast_d(volatile S &s)
{ return dynamic_cast<T>s; }
template <class T, class S> T cast_d(const volatile S &s)
{ return dynamic_cast<T>s; }
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. Moderation policy:
http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/12 Raw View
vandevod@cs.rpi.edu (David Vandevoorde) writes:
>>>>>> "FH" == Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:
>[...]
>FH> template <class T, class S> T cast_d(S &s)
> { return dynamic_cast<T>s; }
>FH> template <class T, class S> T cast_d(const S &s)
> { return dynamic_cast<T>s; }
>FH> template <class T, class S> T cast_d(volatile S &s)
>FH> { return dynamic_cast<T>s; }
>FH> template <class T, class S> T cast_d(const volatile S &s)
>FH> { return dynamic_cast<T>s; }
>
>Isn't the last one sufficient?
No, because 5.2.6[expr.cast.dynamic]/1 states that "dynamic_cast shall
not cast away constness". If you only defined the last one, then code
such as
class Foo : public Bar { /* ... */ };
void f(Bar& x) {
cast_d<Foo&>(x);
}
would be ill-formed, because it would instantiate
cast_d<Foo&, Bar> Foo& cast_d(const volatile Bar &s)
{ return dynaic_cast<Foo&>(s); }
and this dynamic_cast would be casting away constness.
Incidentally, 5.2.6 would seem to imply that dynamic_cast *is* allowed
to cast away volatileness, but I think that is a mistake in the current
draft.
>(and aren't parentheses required in `dynamic_cast<T>(s)'?).
Yes, they are -- thanks for correcting that error.
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: esap@cs.tut.fi (Pulkkinen Esa)
Date: 1996/02/12 Raw View
In article <4fa6d0$115g@news.gate.net>, Ken Walter <solution@gate.net> wrote:
>template <class T, class S> T cast_d( S s) { return dynamic_cast<T>s; }
>Casts could almost be implemented without being part of the language.
>
They can. But it's too much work for the programmer to do it. I've used
a simulation of a dynamic_cast when I didn't have a compiler that supports
them. The problem with such a simulation is that you have to provide
most of the information dynamic_cast uses by yourself (for the second time),
even though you have already provided the compiler with the same
information in the class declaration. Or you can use macro hackery
to do that for you, but that's ugly.
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: esap@cs.tut.fi | everywhere with a class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: vandevod@cs.rpi.edu (David Vandevoorde)
Date: 1996/02/12 Raw View
>>>>> "FH" == Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:
[...]
FH> template <class T, class S> T cast_d(S &s)
{ return dynamic_cast<T>s; }
FH> template <class T, class S> T cast_d(const S &s)
{ return dynamic_cast<T>s; }
FH> template <class T, class S> T cast_d(volatile S &s)
FH> { return dynamic_cast<T>s; }
FH> template <class T, class S> T cast_d(const volatile S &s)
FH> { return dynamic_cast<T>s; }
Isn't the last one sufficient? (and aren't parentheses required in
`dynamic_cast<T>(s)'?).
Daveed
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. Moderation policy:
http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1996/02/05 Raw View
Eugene Radchenko wrote:
> Why don't use, for instance, cast_d instead od
> dynamic_cast (ugh).
This is quite deliberate. Bjarne dislikes casts. So do I.
He didn't invent new style casts (and RTTI) for your convenience,
he invented them to make sure no one else did. Long names were deliberately
chosen to discourage use of casts.
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 web: http://www.maxtal.com.au/~skaller/
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: jason@cygnus.com (Jason Merrill)
Date: 1996/02/08 Raw View
>>>>> Eugene Radchenko <eugene@qsar.chem.msu.su> writes:
> jason@cygnus.com (Jason Merrill) writes
>>>>>>> Eugene Radchenko <eugene@qsar.chem.msu.su> writes:
>>> 1) Clause [temp.res] verse 1 requires that all types dependent on the
>>> template parameter must be qualified by 'typename' keyword - supposedly to
>>> allow checking the template syntax. But it does not help anything as _each_
>>> instance will have to be checked anyway:
>> Requiring 'typename' allows syntactic analysis and some name binding
>> to be done at the point of definition of the template. Older
>> implementations do all name binding at the point of instantiation,
>> which was thought to be confusing.
>> Each instance will indeed have to be checked, but only for semantic
>> correctness, not syntactic.
> And does such a simplification (which does not simplify anything as
> complete recheck is still needed) warrant the introduction of a new
> keyword (why could not at least the 'class' keyword be used like in
> template prefix?).
Because 'class' already has semantics in that position, and a new keyword
is really not a significant problem. If it conflicts with your code, you
can easily work around it with a #define.
> Interestingly, WRT member functions (and especially operator->) the
> decision was roughly inverse (i.e. to perform checking only on the
> per-instance basis and only if given instance is required).
Nope; function templates, like class templates, are parsed immediately to
do name binding according to the new lookup rules.
>>> 2) Clause [temp.dep] verse 5 states that base class scope names hide the
>>> template parameter:
>> This is for orthogonality. Think of the template header as creating a
>> special scope around the class; name lookups in class scope look in the
>> current class, then in base classes, then in the surrounding scope.
> That much I do understand. I only think that such an order is
> counter-intuitive.
Well, other people don't, apparently.
>>> 3) Clause [temp.arg.explicit] verses 2-3 requires that for explicit arg in
>>> member template to be present it must be qualified by 'template' keyword,
>>> e.g.
>>> X *p; p->template alloc<200>();
>>> But to use operator -> we need X class definition anyway - so we know that
>>> alloc() is a template.
>> It is needed in some situations where we do not have the X class definition
>> -- in template definitions, like with typename.
> And what are we supposed to do with function alloc() if we do not have the
> class definition and hence do not know anything about this function?
We only need the 'template' keyword there so we know what '<' means. If
'alloc' is a template, it means "begin template arg list". Otherwise, it
means "less than", and it doesn't matter if 'alloc' is a function or a
field or an enum or whatever; that can wait until semantic analysis at
instantiation time.
Jason
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: vandevod@cs.rpi.edu (David Vandevoorde)
Date: 1996/02/09 Raw View
>>>>> "ER" == "Eugene Radchenko" <eugene@qsar.chem.msu.su> writes:
[...]
>>> 3) Clause [temp.arg.explicit] verses 2-3 requires that for explicit arg in
>>> member template to be present it must be qualified by 'template' keyword,
>>> e.g.
>>> X *p; p->template alloc<200>();
>>> But to use operator -> we need X class definition anyway - so we know that
>>> alloc() is a template.
>> It is needed in some situations where we do not have the X class definition
>> -- in template definitions, like with typename.
ER> And what are we supposed to do with function alloc() if we do not have the
ER> class definition and hence do not know anything about this function?
C++ compilers are not trivial things to write and it makes sense to
decompose the compilation process in well-separated ``phases''. One
such phase is lexical analysis (decomposing the source text into
tokens), another is syntactical analysis (also called parsing; classify
the tokens and their relationship) and yet another one is semantic
analysis (``interpret the classification and relationships determined
during syntactical analysis'').
I may be somwhat innacurate in my descriptions, but feeding back
information from semantic analysis (e.g., ``class X has no member
template alloc'') to syntactic analysis (so that it can find out that
``X::alloc is a data member, not a member function template'') makes
the process harder. The traditional example, is more along the
lines of:
p->alloc<2>(0);
Is this meant to be equivalent to `(p->alloc < 2) > 0' or to the
invocation of a template member function? With the added syntax,
the parser knows without relying on the semantic analysis.
Daveed
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. Moderation policy:
http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Author: "Eugene Radchenko" <eugene@qsar.chem.msu.su>
Date: 1996/01/29 Raw View
Hi people!
I want to share some thoughts on the template section of the (April) draft
standard (BTW, is ASCII version of September one is available somewhere?
Easily editable/reformattable version (e.g. WinWord or RTF) would be even
better).
Generally, I like it very much. In fact while reading it I had that
'Here-is-what-I-longed-for' feeling which I last had (programming-wise)
when reading Stroustroup's book 5 years ago. Some things I do not
understand, however, and would like the committee members to provide
'rationale on demand' and explain what is the point of some finer points.
1) Clause [temp.res] verse 1 requires that all types dependent on the
template parameter must be qualified by 'typename' keyword - supposedly to
allow checking the template syntax. But it does not help anything as _each_
instance will have to be checked anyway:
e.g.
struct X {
static int A;
class B { };
}
template <class T> class Y {
typename T::A *ap; // error in Y<X> - T::A is not a type
T::B *bp; // error - no 'typename'
}
2) Clause [temp.dep] verse 5 states that base class scope names hide the
template parameter:
struct A { struct B{}; };
template <class B, class C> struct X : A {
B b; //A's B
};
However, as base class is the enclosing scope, I would intuitively expect
anything related to the derived class (its template parameter, for
instance) to hide its names. Moreover, we can use A::B to access A's B -
while template parameter is now inaccessible. Also, base class definition
may be inaccessible. Of course, you can change the temp. param. name - but
anyway it is not nice.
3) Clause [temp.arg.explicit] verses 2-3 requires that for explicit arg in
member template to be present it must be qualified by 'template' keyword,
e.g.
X *p; p->template alloc<200>();
But to use operator -> we need X class definition anyway - so we know that
alloc() is a template. Thus this keyword is redundant and likely to be
forgotten (if I am not mistaken, it is in fact missing from some examples
in lib.locale section).
4) Clause [temp.deduct] verse 4. Why the conversions other than Derived* ->
Base* are not allowed in template deduction (at least default conversions
like char->int; user conversions would be even better)?
Best regards Genie
PS. Am I the only one who does not like the current drift in the C++ syntax
from symbolic (C-like)
int a[10];
to verbose (Pascal-like)
var
a: array[0..9] of integer;
way of expressing things? Why don't use, for instance, cast_d instead od
dynamic_cast (ugh). Yeah, I know we are not using 10-cps terminals Richie
(sp?) did, but anyway... (and it consumes compiler memory space :-)
--
--------------------------------------------------------------------
Eugene V. Radchenko Research associate, Computer Chemistry
E-mail: eugene@qsar.chem.msu.su Fax: +7-(095)939-0290
Ordinary mail: Chair of Organic Chemistry, Department of Chemistry,
Moscow State University, 119899 Moscow, Russia
***************** Disappearances are deceptive *******************
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: jason@cygnus.com (Jason Merrill)
Date: 1996/01/30 Raw View
>>>>> Eugene Radchenko <eugene@qsar.chem.msu.su> writes:
> 1) Clause [temp.res] verse 1 requires that all types dependent on the
> template parameter must be qualified by 'typename' keyword - supposedly to
> allow checking the template syntax. But it does not help anything as _each_
> instance will have to be checked anyway:
Requiring 'typename' allows syntactic analysis and some name binding
to be done at the point of definition of the template. Older
implementations do all name binding at the point of instantiation,
which was thought to be confusing.
Each instance will indeed have to be checked, but only for semantic
correctness, not syntactic.
> 2) Clause [temp.dep] verse 5 states that base class scope names hide the
> template parameter:
This is for orthogonality. Think of the template header as creating a
special scope around the class; name lookups in class scope look in the
current class, then in base classes, then in the surrounding scope.
Note that template parameters used as base types are not affected by this
rule, since name binding is done on the template definition, before the
base is known.
> 3) Clause [temp.arg.explicit] verses 2-3 requires that for explicit arg in
> member template to be present it must be qualified by 'template' keyword,
> e.g.
> X *p; p->template alloc<200>();
> But to use operator -> we need X class definition anyway - so we know that
> alloc() is a template.
It is needed in some situations where we do not have the X class definition
-- in template definitions, like with typename.
Jason
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: jason@cygnus.com (Jason Merrill)
Date: 1996/02/01 Raw View
>>>>> Jason Merrill <jason@cygnus.com> writes:
>>>>> Eugene Radchenko <eugene@qsar.chem.msu.su> writes:
>> 3) Clause [temp.arg.explicit] verses 2-3 requires that for explicit arg in
>> member template to be present it must be qualified by 'template' keyword,
>> e.g.
>> X *p; p->template alloc<200>();
>> But to use operator -> we need X class definition anyway - so we know that
>> alloc() is a template.
> It is needed in some situations where we do not have the X class definition
> -- in template definitions, like with typename.
But then, the rule in the WP applies regardless of whether we know about X.
I conclude that the idea was to allow the parser to do its work without
peeking into classes to find names used after . or ->; another rule along
the same lines requires that a scope used after . or -> have the same
meaning in the ambient scope and the scope of the object specified.
Jason
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]