From 1411838245497397800
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,ede379f5dbbc1549
X-Google-Attributes: gidf78e5,public
From: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Subject: Re: Suggestion: "typeof" keyword
Date: 1999/08/19
Message-ID: <37BBE6CC.FE2475E5@physik.tu-muenchen.de>
X-Deja-AN: 514751384
X-Nntp-Posting-Host: coulomb.t30.physik.tu-muenchen.de
Content-Transfer-Encoding: 7bit
Approved: stephen.clamage@sun.com (comp.std.c++)
References: <7nt3vl$1oe$1@nnrp1.deja.com> <7oh7o8$t3f$1@nnrp1.deja.com> <7ol6hi$ej9$2@news.BelWue.DE> <cTiioXAhAwr3Ew$X@robinton.demon.co.uk> <t7d7ww1vrz.fsf@calumny.jyacc.com> <e4DSyfA4ALs3Ew0Q@robinton.demon.co.uk> <t7r9laz5hj.fsf@calumny.jyacc.com> <7oup0a$8g2$1@nnrp1.deja.com> <37B3C2AD.5AB722AE@lucent.com> <37B5A571.449B@wanadoo.fr> <37B908A8.717CAC2C@lucent.com> <CVJFZFAbaWu3Ew15@robinton.demon.co.uk> <7pcvjs$tk4$1@nnrp1.deja.com> <user-1808991258230001@aus-as3-121.io.com>
X-Accept-Language: German/Germany, de-DE, German, de, en
X-UID: 0000000001
X-Status: $$$T
Content-Type: text/plain; charset=us-ascii
Organization: [posted via] Leibniz-Rechenzentrum, Muenchen (Germany)
Mime-Version: 1.0
Newsgroups: comp.std.c++
Originator: clamage@taumet


blargg wrote:

[...]

> > 3 When applied to a reference or a reference type,
> >   the result is the referenced type. When applied
> >   to a constant reference or constant reference type,
> >   the resulting type is not constant.
> 
> Bad. Why not allow the user to decide to remove the reference?
> 
> Bad. Call-through doesn't work.
> 
>     int& func();
> 
>     void g() {
>         typeof (func()) ret = func();
>         ret = 20; // oops, modified local variable ret
>     }

If we go to modify the variable, it only makes sense if we know
from the beginning that the function returns a reference. And
then we can put the reference litterally.
Indeed, if typeof makes the reference for us, it's even more
dangerous: change the function to return int instead int&,
and the compiler won't even warn us - if the reference is
explicit, it would complaion about binding an rvalue
to a non-const reference (if the return value gets const,
you get the error at the assignment line).

Note that this change may come as side effect if (erroneously)
making an object const, if func is an accessor into the
object, since often the accessors come in pairs like:

int& X::get() { ... }
int X::get() const { ... }

You _do_ want the compiler to warn you here, don't you?

> 
> If they don't want the reference, they can remove it themselves:
> 
>     template<typename T>
>     struct remove_ref {
>         typedef T type;
>     };
> 
>     template<typename T>
>     struct remove_ref<T&> {
>         typedef T type;
>     };
> 
>     void g() {
>         remove_ref<typeof (func())>::type ret = func(); // type is int
> 
>         ret = 20; // OK, we know we made a copy
>     }
> 
> >     vector<int> v;
> >     typeof(v[0]) a; // int, not int&
> >
> >     const vector<int>& cv = v;
> >     typeof(cv[0]) b; // int, not const int&
> 
> And your example shows exactly why it shouldn't be that way.
> 
> Like your argument (I think it was you) for not removing const, I argue
> for not removing ref, since both can be done by the user with a template.

I actually did that argument (But maybe I have missed the same
argument by someone else).
However, with references, it's more complicated:

int* p;
typeof(*p) foo = *p; // int foo = p, or int& foo = p?

Even the following is not entirely clear:

int i;
typeof(i) i2=i; // i is modifiable; should i2 be a reference?

What about:

int i;
int& i2 = i;
typeof(i2) i3 = i2;
          // why should this case different from the previous?

The point is that references are defined to be "the same"
as the referenced variable - except on initialisation, there
is currently _no_ way to distinguish a reference from the
referenced type (except indirectly, by noting that other
variables change as well; however even then, you can't write
code that detects which one is the original and which one
is the reference). Making typeof reference-aware would break
that.

> 
> Not that I think this construct is very good. Having to duplicate the
> expression in many cases is just lame. I like "declare" ("var") much
> better.

However, declare fails as soon as you get to return types
of functions (esp. if the definition is not in the current
translation unit):

// scalar product of two vectors
template<class T1, class T2>
 typeof(T1() * T2()) operator*(Vector<T1> const&,
                               Vector<T2> const&);

[...]

> > 5 In the context of a typeof expression, if T is any
> >   type then T() denotes a temporary object of that
> >   type, even if the type has no default constructor.
> >   (The expression is not evaluated, so it does not
> >   matter whether the object can be correctly
> >   initialized.)
> 
> Joy. I don't like typeof in practice :-)
> 
> The closest to typeof that I think would be reasonable would be allowing
> type members of a class to be referenced off a pointer/reference to the
> object (with the lhs *not* being evaluated, since it could appear
> anywhere):
> 
>     template<class Container>
>     void f( Container& c ) {
>         for ( c.iterator p = c.begin(); c != c.end(); ++c ) {
>             // ...
>         }
>     }
> 
> To get typeof from this
> 
>     template<typename T>
>     struct extract_type {
>         typedef T type;
>     };
> 
>     template<typename T>
>     extract_type<T>& typeof( T& );
> 
> // use
> 
>     typeof (foo).type foo_copy( foo );
> 
> Or, if one really wanted the same syntax,
> 
>     #define typeof( expr )  typeof (expr).type

Interesting point. So the object.type idiom would be
as powerful as the typeof idiom. (However, maybe the
syntax object::type would be preferrable, since in all
other cases, everything left of the "." is evaluated,
so the "." notation could cause confusion.). The rule
that nothing on the left of "::" is evaluated at run time
would be simple, and general (currently, nothing which
could possibly be evaluated at run time is allowed at all).

Being equally powerful, the "object scope" solution has
the advantage of not introducing a new keyword, and of
being more readable if a typedef is already provided,
as with c.iterator (or c::iterator).

[...]


[ 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              ]




