Topic: External Methods


Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/08/07
Raw View
Christopher Eltschka wrote:
>
 [snip]
>
> However, I still would like to have a way to do this, just more
> explicit. For example in form of a construct like
>
>   funptr = member_to_global_function(object, Class::memfun);
>
> (which looks as expensive as it is).
>
> However, I doubt that this would get to any future standard
> (I'm not even sure that it is possible on any platform).
> But as local extension on platforms where it is possible,
> it would be a nice thing IMHO.

You're asking for a feature that lets you convert a class member
function pointer and a specific object (of that class type) into
a pointer-like object, which can be dereferenced (called) like an
ordinary function pointer later.

Well, nothing is stopping you from writing a template class that
implements most of such a critter.  Perhaps a good starting point
would be something like:

    template <class Obj>
    class ObjFuncPtr    // Object+function pointer
    {
    public:
                ObjFuncPtr(Obj &o, void (*f)());
        void    operator ()() const;

    private:
        Obj &   m_obj;              // The object
        void    (Obj::*m_func)();   // The function pointer
    };

When you construct an ObjFuncPtr object, you associate it with an
object 'o' of type Obj and a member function 'f' within class Obj.
Then you call the member function through the new object it by
using operator()(), which passes 'o' as the 'this' pointer to the
member function.

Obviously, this is only a basic starting point.  Implementing the
rest is left as an exercise for the reader...

-- David R. Tribble, dtribble@technologist.com --
-- Win95: Start me up... You make a grown man cry...


[ 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: 1998/08/06
Raw View
AllanW@my-dejanews.com wrote:
>
> In article <35C08AE7.1BED95E3@physik.tu-muenchen.de>,
>   Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> > Pete Becker wrote:
> > > But member functions are not like ordinary functions, so analogies with
> > > ordinary functions can be misleading. The rule is quite clear:
> > >
> > >         A pointer to member is only formed when an
> > >         explicit & is used and its operand is a
> > >         qualified-id not enclosed in parentheses.
> > >
> > > And, in fact, taking the address of a data member is a good example of
> > > why this should not work for functions. When you take &int_var inside a
> > > member function you get a normal pointer to int_var. That is, apply * to
> > > it and you have an int. What would analogous behavior for a member
> > > function be?
> >
> > To provide a function pointer to a trampoline created on-the-fly,
> > which calls the given member function on the given object with
> > the parameters given on the call through function pointer.
> > Example:
> >
> > typedef void (*ofp)(int); // ordinary function pointer
> >
> > class X
> > {
> >   void foo(int);
> >   void bar(int);
> >   ofp get_bar() { return &bar; }
> > };
> >
> > X x, y;
> >
> > void of(int)
> > {
> > }
> >
> > int main()
> > {
> >   ofp f=of;
> >   f(3); // calls of(3)
> >
> >   f=&x.foo;
> >   f(5); // calls x.foo(5)
> >
> >   f=y.get_bar();
> >   f(10); // calls y.bar(10)
> > }
>
> I would hate for this to be automatic, because it could
> be used carelessly with no warning. The "ofp" type would
> have much more overhead than a typical pointer to a
> global-or-static function.

I agree that doing this automatically would probably not a good
idea. However the question is what semantics this construct
would have if it were allowed, and IMHO this is the only sensible
possibility.

However, I still would like to have a way to do this, just more
explicit. For example in form of a construct like

  funptr = member_to_global_function(object, Class::memfun);

(which looks as expensive as it is).

However, I doubt that this would get to any future standard
(I'm not even shure that it is possible on any platform).
But as local extension on platforms where it is possible,
it would be a nice thing IMHO.

>
> In cases where it is useful, something very similar can
> be done explicitly (with the proviso that the "ofp" can
> be passed to a template class, but not easily passed to
> a non-template class). See the STL's "functor" classes
> for excellent examples of how to do this.

No, it can easily passed to a function template (automatically
creating a function), and it can be used to explicitly
instantiate a class template (creating a class).
But is cannot be passed to a normal function pointer, and there
is no way to do that in standard C++, since you cannot generate
code on the fly yourself. Especially you cannot pass it to a C
function.


[ 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: zalman@netcom.com (Zalman Stern)
Date: 1998/08/04
Raw View
AllanW@my-dejanews.com wrote:
: That's probably true, but I don't think there's any cases of it failing
: where the member-function idiom ought to work.  Thus, it ought to
: satisfy anyone who wants to add conceptual member functions in cases
: where the class has already been fully defined.

template <class T>
void DoSomething(T &target) {
 target.DoSomething();
}

class NotDoable {
 /* A bunch of methods but no DoSomething() method. */
};

{
 NotDoable a;

 DoSomething(a); // An error.
}

If we added:

 external_method // Or whatever.
 void NotDoable::DoSomething() {
 }

Then the above template invocation is allowed. There are other techniques
for solving the problem, such as making a subclass or writing a adapter
class. However one can see "attractive immediacy" in the above idea. Which
doesn't necessarily make it a good idea... (Haven't really decided yet
myself.)

-Z-
---
[ 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: 1998/07/30
Raw View
Steve Clamage wrote:
>
> zalman@netcom.com (Zalman Stern) writes:
>
> >Another syntactic lack I see is the inability to define something that
> >looks like a data member but that uses setter/getter methods. (E.g. try
> >defining 2D and 3D point classes that derive from a common vector class. To
> >use such classes, one cannot merely write "point.x". One must do something
> >like "point[xCoord]" or "point.x()".
>
> That's a problem inherited from C. Using just the name of a
> function without parens already has a meaning: the address
> of the function. There was no good way to allow it also to
> mean that the function should be called.

There's a quite simple way:

Add a standard conversion from T(*)() to T, if T is not void.
The conversion is done by calling the function.

This would not change any program where a function is used as function
pointer (even in C++, since no conversion is always better than
conversion to T), with one exception: If the function pointer was
casted to a different type with an old-style cast *and* the result
type was accidentally equal to the type casted to. In C++ this could
be easily resolved by using reinterpret_cast.
---
[ 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: 1998/07/30
Raw View
Pete Becker wrote:
>=20
> AllanW@my-dejanews.com wrote:
> >
> > In article <35BD10B5.60E932BC@acm.org>,
> >   Pete Becker <petebecker@acm.org> wrote:
> > > The first two have never been legal, except with Microsoft's compil=
er.
> >
> > I don't think this was ever legal on Microsoft, either.  David,
> > didn't you mean to make memb a member function, instead of a
> > member variable?
> >
> > Restate the example:
>  >     class Foo {
>  >         int     memb();
>  >         void    bar();
>  >     };
>  >
>  >     void Foo::bar() {
>  >         int (*x)() =3D memb;        // Needs '&' ?
>  >         int (*y)() =3D &memb;       // Needs 'Foo::' ?
>  >         int (*z)() =3D &Foo::memb;  // Okay
>  >     }
>  >
> > I hope the answer is that all three are legal.
>=20
> No, that's the actual question that I answered. The first two are
> illegal, now that memb is a member function.
>=20
> > It seems intuitive
> > because of the direct parallel:
> >     int     GlobalFunc();
> >     void    GlobalBar();
> >
> >     void GlobalBar() {
> >         int (*x)() =3D GlobalFunc;        // Doesn't need &, does it?
> >         int (*y)() =3D &GlobalFunc;       // Okay
>=20
> But member functions are not like ordinary functions, so analogies with
> ordinary functions can be misleading. The rule is quite clear:
>=20
>         A pointer to member is only formed when an
>         explicit & is used and its operand is a
>         qualified=ADid not enclosed in parentheses.
>=20
> And, in fact, taking the address of a data member is a good example of
> why this should not work for functions. When you take &int_var inside a
> member function you get a normal pointer to int_var. That is, apply * t=
o
> it and you have an int. What would analogous behavior for a member
> function be?

To provide a function pointer to a trampoline created on-the-fly,
which calls the given member function on the given object with
the parameters given on the call through function pointer.
Example:

typedef void (*ofp)(int); // ordinary function pointer

class X
{
  void foo(int);
  void bar(int);
  ofp get_bar() { return &bar; }
};

X x, y;


void of(int)
{
}

int main()
{
  ofp f=3Dof;
  f(3); // calls of(3)

  f=3D&x.foo;
  f(5); // calls x.foo(5)

  f=3Dy.get_bar();
  f(10); // calls y.bar(10)
}
---
[ 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: 1998/07/30
Raw View
AllanW@my-dejanews.com wrote:
>
> In article <6pkgm9$sko$1@news3.isdnet.net>,
>   "=?iso-8859-1?B?TG/vYyBUculnYW4=?=" <loic.tregan@hol.fr> wrote:
> > Steve Clamage <clamage@Eng.Sun.COM> wrote in message
> > 6oeppc$sa2@engnews1.Eng.Sun.COM...
> > >One important property of a class is that every function that
> > >has access to non-public members is declared in the class. If
> > >that were not the case, you could never change any part of
> > >a class without breaking programs you don't know about; any
> > >program might have inserted its own member functions that
> > >depended on implementation details.
> >
> > so allow external methods when they do not access private/protected data.
>
> We can do that now, albeit with slightly different syntax.  This case
> is known as "Global functions where the first parameter is a reference
> to the class."

It's not really the same:

class A {};

class B { public: operator A(); }

void global(A const&, int);

// hypothetical:
void A::member(int) const;

int main()
{
  global(B, 6); // Ok: B converted to A
  B.member(6);  // Error: No function B::member(int)
}

However, you could make a trick:

class MustBeConstA
{
  friend void global(MustBeConstA, int);
public:
  MustBeConstA(A const& a): theA(a) {}
  MustBeConstA(MustBeConstA const& other): theA(other.theA) {}
private:
  A const& theA;
};

void global(MustBeConstA a, int x)
{
  // use a.theA instead of simply a
}

int main()
{
  global(B, 6); // Error: no conversion B->MustBeConstA
}
---
[ 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: Jason Merrill <jason@cygnus.com>
Date: 1998/08/01
Raw View
>>>>> Pete Becker <petebecker@acm.org> writes:

> AllanW@my-dejanews.com wrote:
>>
>> class Foo {
>>   int     memb();
>>   void    bar();
>> };
>>
>> void Foo::bar() {
>>   int (*x)() = memb;        // Needs '&' ?
>>   int (*y)() = &memb;       // Needs 'Foo::' ?
>>   int (*z)() = &Foo::memb;  // Okay
>> }
>>
>> I hope the answer is that all three are legal.

> No, that's the actual question that I answered. The first two are
> illegal, now that memb is a member function.

As is the third, since you're trying to assign an
  int (Foo::*)()
to an
  int (*)()

Jason
---
[ 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: AllanW@my-dejanews.com
Date: 1998/08/01
Raw View
In article <35C08DD9.91678AB8@physik.tu-muenchen.de>,
  Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> AllanW@my-dejanews.com wrote:
> >
> > In article <6pkgm9$sko$1@news3.isdnet.net>,
> >   "=?iso-8859-1?B?TG/vYyBUculnYW4=?=" <loic.tregan@hol.fr> wrote:
> > > Steve Clamage <clamage@Eng.Sun.COM> wrote in message
> > > 6oeppc$sa2@engnews1.Eng.Sun.COM...
> > > >One important property of a class is that every function that
> > > >has access to non-public members is declared in the class. If
> > > >that were not the case, you could never change any part of
> > > >a class without breaking programs you don't know about; any
> > > >program might have inserted its own member functions that
> > > >depended on implementation details.
> > >
> > > so allow external methods when they do not access private/protected data.
> >
> > We can do that now, albeit with slightly different syntax.  This case
> > is known as "Global functions where the first parameter is a reference
> > to the class."
>
> It's not really the same:

[Edited slightly]
> class A {};
> class B { public: operator A(); }
> void global(A const&, int);
> void A::member(int) const; // hypothetical
>
> int main()
> {
>   global(B, 6); // Ok: B converted to A
>   B.member(6);  // Error: No function B::member(int)
> }

I think you meant to write main() like this:
    int main(int,char**) {
        B b;
        global(b, 6); // Calls global(A const&,int)
        b.member(6); // Error because member() is a member of A but not B
    }

So your point is that such a global function works in cases where
the member-function idiom ought to fail, right?

That's probably true, but I don't think there's any cases of it failing
where the member-function idiom ought to work.  Thus, it ought to
satisfy anyone who wants to add conceptual member functions in cases
where the class has already been fully defined.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: AllanW@my-dejanews.com
Date: 1998/08/01
Raw View
In article <35C08AE7.1BED95E3@physik.tu-muenchen.de>,
  Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
> Pete Becker wrote:
> > But member functions are not like ordinary functions, so analogies with
> > ordinary functions can be misleading. The rule is quite clear:
> >
> >         A pointer to member is only formed when an
> >         explicit & is used and its operand is a
> >         qualified-id not enclosed in parentheses.
> >
> > And, in fact, taking the address of a data member is a good example of
> > why this should not work for functions. When you take &int_var inside a
> > member function you get a normal pointer to int_var. That is, apply * to
> > it and you have an int. What would analogous behavior for a member
> > function be?
>
> To provide a function pointer to a trampoline created on-the-fly,
> which calls the given member function on the given object with
> the parameters given on the call through function pointer.
> Example:
>
> typedef void (*ofp)(int); // ordinary function pointer
>
> class X
> {
>   void foo(int);
>   void bar(int);
>   ofp get_bar() { return &bar; }
> };
>
> X x, y;
>
> void of(int)
> {
> }
>
> int main()
> {
>   ofp f=of;
>   f(3); // calls of(3)
>
>   f=&x.foo;
>   f(5); // calls x.foo(5)
>
>   f=y.get_bar();
>   f(10); // calls y.bar(10)
> }

I would hate for this to be automatic, because it could
be used carelessly with no warning. The "ofp" type would
have much more overhead than a typical pointer to a
global-or-static function.

In cases where it is useful, something very similar can
be done explicitly (with the proviso that the "ofp" can
be passed to a template class, but not easily passed to
a non-template class). See the STL's "functor" classes
for excellent examples of how to do this.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: AllanW@my-dejanews.com
Date: 1998/08/01
Raw View
In article <35BFC27B.F608B43D@acm.org>,
  Pete Becker <petebecker@acm.org> wrote:
> AllanW@my-dejanews.com wrote:
> >
> > In article <35BD10B5.60E932BC@acm.org>,
> >   Pete Becker <petebecker@acm.org> wrote:
> > > The first two have never been legal, except with Microsoft's compiler.
> >
> > I don't think this was ever legal on Microsoft, either.  David,
> > didn't you mean to make memb a member function, instead of a
> > member variable?
> >
> > Restate the example:
>  >     class Foo {
>  >         int     memb();
>  >         void    bar();
>  >     };
>  >
>  >     void Foo::bar() {
>  >         int (*x)() = memb;        // Needs '&' ?
>  >         int (*y)() = &memb;       // Needs 'Foo::' ?
>  >         int (*z)() = &Foo::memb;  // Okay
>  >     }
>  >
> > I hope the answer is that all three are legal.
>
> No, that's the actual question that I answered. The first two are
> illegal, now that memb is a member function.
>
> > It seems intuitive because of the direct parallel:
> >     int     GlobalFunc();
> >     void    GlobalBar();
> >
> >     void GlobalBar() {
> >         int (*x)() = GlobalFunc;        // Doesn't need &, does it?
> >         int (*y)() = &GlobalFunc;       // Okay
>
> But member functions are not like ordinary functions, so analogies with
> ordinary functions can be misleading. The rule is quite clear:
>
>  A pointer to member is only formed when an
>  explicit & is used and its operand is a
>  qualified-id not enclosed in parentheses.
>
> And, in fact, taking the address of a data member is a good example of
> why this should not work for functions. When you take &int_var inside a
> member function you get a normal pointer to int_var. That is, apply * to
> it and you have an int. What would analogous behavior for a member
> function be?

Apparently, what I expected is not what I would get.  Since you seem
to be asking what I would have expected, please don't bother to tell
me that anything after this point in this message is inaccurate (I
know that, now).

In a global function, &int_var returns a normal pointer to an int.
In a non-static member function, I would expect &int_var to also
return a normal pointer to an int, even if int_var was a data
member -- it would be the address of that member of the current
instanciation, equivalent to &this->int_var.  (BTW, is
&this->int_var legal?)
In a static member function, I would expect &int_var to return a
normal pointer to an int, unless int_var was a data member -- then
it would return a pointer to member, equivalent to &Foo::int_var.
But this wouldn't mistakenly make code like
    int *ptr = &int_var;
legal, because this attempts to initialize a normal pointer to int
with a value of type member pointer to int.  Such an initialization
is illegal, weather the class name is defined or not.  However, it
would make code like this legal:
    int (Foo::*ptr) = &mem_int;
This would become legal, even though Foo:: isn't specified, and even
though we continue to completely analyze the rhs without considering
the data type of the lhs.

In a global function, func or &func both return a normal pointer to
the function. This is true even if func is in a scope, provided it
can be used without that scope name; i.e.
    using std::strcpy;
    char* (*funcptr)(char*,const char*);
    funcptr = strcpy;
In a member function, static or not, I would expect &func to return a
normal pointer to the function if it was a normal function, and a
member pointer to the function if it was a non-static member function.
Again, this wouldn't mistakenly make code such as
    char* (*funcptr)(char*,const char*) = &mem_func;
legal, because this attempts to initialize a normal function pointer
with a value of type member function pointer. Such an initialization
is illegal, weather the class name is defined or not. However, it
would make this declaration legal within a Foo member function:
    char* (Foo::*Funcptr)(char*,const char*) = mem_func;
This would become legal, even though neither & nor Foo:: is specified,
and even though we continue to completely analyze the rhs without
considering the data type of the lhs.

Essentially, I'm suggesting that (ignoring special cases, such as a
class which defines operator& private) &x should always be legal if
x is in scope; the exact type of &x would be dependant on the type
of x and also on the current scope.  I don't think that this would
make the compiler much more difficult to write or the user code more
difficult to maintain. Furthermore, if x happens to be a function
(member or otherwise), then the & would be implicit and optional
unless parenthesis were used. I think that this almost describes the
way that C works, except that of course in C there is no such thing
as member data or member functions.

I now know that this isn't the way it works in C++, but until I found
that out, this is what I expected to work.  I think that I was misled
by Microsoft, because I think that some of these examples that
shouldn't work did happen to work there, without any errors or
warnings. (But I'm not even certain of that -- I haven't tried it,
recently.  Besides, this group is about C++ standards, not about
Microsoft.)

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: Pete Becker <petebecker@acm.org>
Date: 1998/07/30
Raw View
Bill Wade wrote:
>
> Pete Becker wrote in message <35BD10B5.60E932BC@acm.org>...
> >David R Tribble wrote:
 > >>     class Foo
 > >>     {
 > >>         int     memb;
 > >>         [...]
 > >>     };
 > >>
 > >>     void Foo::bar()
 > >>     {
 > >>         int * x = memb;        // Needs '&' ?
 > >>         int * y = &memb;       // Needs 'Foo::' ?
 > >>         int * z = &Foo::memb;  // Okay
 > >>     }
> >The first two have never been legal, except with Microsoft's compiler.
>
> I'd say only the second is legal (and historically so).  The lhs of all of
> the assignments is ptr to int.  The only rhs that is ptr to int is the
> second one.

Whoops, I read it too hastily. Now that you've removed the distracting
mention of bar(), I see what it's getting at. memb is a data member, not
a function. The first is illegal, needs '&'. The second is legal, takes
the address of the integer this->memb. The third is illegal, because it
attempts to assign a pointer-to-member to an ordinary pointer.

>
> I seem to recall seeing at one time a compiler (possibly MS) that supported
>
> struct foo
> {
>   int m;
>   void bar();
> };
> void foo::bar()
> {
>   int foo::*p1 = &m;      // Standard requires foo:: on rhs
>   int foo::*p2 = &foo::m; // ok
> }
>
> but MSVC++5.0, SR2 seems to get this correct (and rejects the first
> commented line)

That's the issue I was talking about, although it wasn't the one you
were talking about. Sorry about the confusion.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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: AllanW@my-dejanews.com
Date: 1998/07/30
Raw View
In article <6pkgm9$sko$1@news3.isdnet.net>,
  "=?iso-8859-1?B?TG/vYyBUculnYW4=?=" <loic.tregan@hol.fr> wrote:
> Steve Clamage <clamage@Eng.Sun.COM> wrote in message
> 6oeppc$sa2@engnews1.Eng.Sun.COM...
> >One important property of a class is that every function that
> >has access to non-public members is declared in the class. If
> >that were not the case, you could never change any part of
> >a class without breaking programs you don't know about; any
> >program might have inserted its own member functions that
> >depended on implementation details.
>
> so allow external methods when they do not access private/protected data.

We can do that now, albeit with slightly different syntax.  This case
is known as "Global functions where the first parameter is a reference
to the class."

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: Pete Becker <petebecker@acm.org>
Date: 1998/07/30
Raw View
AllanW@my-dejanews.com wrote:
>=20
> In article <35BD10B5.60E932BC@acm.org>,
>   Pete Becker <petebecker@acm.org> wrote:
> > The first two have never been legal, except with Microsoft's compiler.
>=20
> I don't think this was ever legal on Microsoft, either.  David,
> didn't you mean to make memb a member function, instead of a
> member variable?
>=20
> Restate the example:
 >     class Foo {
 >         int     memb();
 >         void    bar();
 >     };
 >=20
 >     void Foo::bar() {
 >         int (*x)() =3D memb;        // Needs '&' ?
 >         int (*y)() =3D &memb;       // Needs 'Foo::' ?
 >         int (*z)() =3D &Foo::memb;  // Okay
 >     }
 >=20
> I hope the answer is that all three are legal. =20

No, that's the actual question that I answered. The first two are
illegal, now that memb is a member function.

> It seems intuitive
> because of the direct parallel:
>     int     GlobalFunc();
>     void    GlobalBar();
>=20
>     void GlobalBar() {
>         int (*x)() =3D GlobalFunc;        // Doesn't need &, does it?
>         int (*y)() =3D &GlobalFunc;       // Okay

But member functions are not like ordinary functions, so analogies with
ordinary functions can be misleading. The rule is quite clear:

 A pointer to member is only formed when an
 explicit & is used and its operand is a=20
 qualified=ADid not enclosed in parentheses.

And, in fact, taking the address of a data member is a good example of
why this should not work for functions. When you take &int_var inside a
member function you get a normal pointer to int_var. That is, apply * to
it and you have an int. What would analogous behavior for a member
function be?

--=20
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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: Anatoli <anatoli@see.my.sig>
Date: 1998/07/29
Raw View
E932BC@acm.org>
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Path:
NNTP-Posting-Host: arava.ptc.com
Lines: 30

Pete Becker wrote:
>
> David R Tribble wrote:
> > Does this mean that the following is (now) illegal?:
> >
> >     class Foo
> >     {
> >         int     memb;
> >         void    bar();
> >         ...
> >     };
> >
> >     void Foo::bar()
> >     {
> >         int * x = memb;        // Needs '&' ?
> >         int * y = &memb;       // Needs 'Foo::' ?
> >         int * z = &Foo::memb;  // Okay
> >     }
> >
>
> The first two have never been legal, except with Microsoft's compiler.

Wait, wait.  Expression "memb" is of type "int", "&memb" is "int*",
and "&Foo::memb" is "int Foo::*".  So only the second assignment
is valid.

If memb is a *static* member, then "&Foo::memb" is of type "int*"
and the third assignment is also valid.
--
Regards
Anatoli (anatoli at ptc dot com) -- opinions aren't
---
[ 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: "Bill Wade" <bill.wade@stoner.com>
Date: 1998/07/29
Raw View
Pete Becker wrote in message <35BD10B5.60E932BC@acm.org>...
>David R Tribble wrote:
>>     class Foo
>>     {
>>         int     memb;
>>         [...]
>>     };
>>
>>     void Foo::bar()
>>     {
>>         int * x = memb;        // Needs '&' ?
>>         int * y = &memb;       // Needs 'Foo::' ?
>>         int * z = &Foo::memb;  // Okay
>>     }
>The first two have never been legal, except with Microsoft's compiler.

I'd say only the second is legal (and historically so).  The lhs of all of
the assignments is ptr to int.  The only rhs that is ptr to int is the
second one.

I seem to recall seeing at one time a compiler (possibly MS) that supported

struct foo
{
  int m;
  void bar();
};
void foo::bar()
{
  int foo::*p1 = &m;      // Standard requires foo:: on rhs
  int foo::*p2 = &foo::m; // ok
}

but MSVC++5.0, SR2 seems to get this correct (and rejects the first
commented line)
---
[ 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?B?TG/vYyBUculnYW4=?=" <loic.tregan@hol.fr>
Date: 1998/07/29
Raw View
Steve Clamage <clamage@Eng.Sun.COM> wrote in message
6oeppc$sa2@engnews1.Eng.Sun.COM...
>One important property of a class is that every function that
>has access to non-public members is declared in the class. If
>that were not the case, you could never change any part of
>a class without breaking programs you don't know about; any
>program might have inserted its own member functions that
>depended on implementation details.

so allow external methods when they do not access private/protected data.
---
[ 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@my-dejanews.com
Date: 1998/07/29
Raw View
In article <35BCACD0.7CE7@noSPAM.central.beasys.com>,
  dtribble@technologist.com wrote:
> David R Tribble wrote:
>  [Talking about leaving off the '()' for member functions taking no
>  args, so that resemble member variables]...
> >> Oops.  I forgot about the fact that naming a function automatically
> >> decomposes into a pointer to that function.
>
> Pete Becker wrote:
> > You didn't forget it, 'cause it ain't so. The only syntax for getting
> > a pointer to a member is &class::member.
>
> Does this mean that the following is (now) illegal?:

The following has always been illegal.

>     class Foo
>     {
>         int     memb;
>         void    bar();
>         ...
>     };
>
>     void Foo::bar()
>     {
>         int * x = memb;        // Needs '&' ?

Needs &Foo::

>         int * y = &memb;       // Needs 'Foo::' ?

Yes.

>         int * z = &Foo::memb;  // Okay
>     }
>
> Or were you just referring to situations outside of class members
> (which require Koenig name lookup)?

Koenig lookup has nothing to do with it.

> Personally, I'm happy that an explicit '&' is required, if that's
> now the case.

That has always been the case for non-static member functions, and is
not the case today for non-member functions.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/29
Raw View
David R Tribble wrote:
>> Does this mean that the following is (now) illegal?:
>>
>>     class Foo
>>     {
>>         int     memb;
>>         void    bar();
>>         ...
>>     };
>>
>>     void Foo::bar()
>>     {
>>         int * x = memb;        // 1. Needs '&' ?
>>         int * y = &memb;       // 2. Needs 'Foo::' ?
>>         int * z = &Foo::memb;  // 3. Okay
>>     }

Pete Becker wrote:
> The first two have never been legal, except with Microsoft's compiler.

Not enough caffeine...

What I meant to ask was, are these illegal?:

    class Foo
    {
        int          memb;
        void         bar();
        static void  baz();
        ...
    };

    void Foo::bar()
    {
        void  (*ap)() = baz;       // A. Needs '&Foo::' ?
        void  (*bp)() = Foo::baz;  // B. Needs '&'?
        void  (*cp)() = &baz;      // C. Needs 'Foo::' ?
        void  (*dp)() = &Foo::baz; // D. Okay
    }

But I'm surprised that [2] above is illegal.  Is this also
illegal?:

        int * y2 = &this->memb;    // 4. Needs 'Foo::' ?

-- David R. Tribble, dtribble@technologist.com --
---
[ 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: AllanW@my-dejanews.com
Date: 1998/07/29
Raw View
In article <35BD10B5.60E932BC@acm.org>,
  Pete Becker <petebecker@acm.org> wrote:
> David R Tribble wrote:
> > Does this mean that the following is (now) illegal?:
> >
> >     class Foo
> >     {
> >         int     memb;
> >         void    bar();
> >         ...
> >     };
> >
> >     void Foo::bar()
> >     {
> >         int * x = memb;        // Needs '&' ?
> >         int * y = &memb;       // Needs 'Foo::' ?
> >         int * z = &Foo::memb;  // Okay
> >     }
> >
>
> The first two have never been legal, except with Microsoft's compiler.

I don't think this was ever legal on Microsoft, either.  David,
didn't you mean to make memb a member function, instead of a
member variable?

Restate the example:
    class Foo {
        int     memb();
        void    bar();
    };

    void Foo::bar() {
        int (*x)() = memb;        // Needs '&' ?
        int (*y)() = &memb;       // Needs 'Foo::' ?
        int (*z)() = &Foo::memb;  // Okay
    }

I hope the answer is that all three are legal.  It seems intuitive
because of the direct parallel:
    int     GlobalFunc();
    void    GlobalBar();

    void GlobalBar() {
        int (*x)() = GlobalFunc;        // Doesn't need &, does it?
        int (*y)() = &GlobalFunc;       // Okay
    }

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/27
Raw View
David R Tribble wrote:
 [Talking about leaving off the '()' for member functions taking no
 args, so that resemble member variables]...
>> Oops.  I forgot about the fact that naming a function automatically
>> decomposes into a pointer to that function.

Pete Becker wrote:
> You didn't forget it, 'cause it ain't so. The only syntax for getting
> a pointer to a member is &class::member.

Does this mean that the following is (now) illegal?:

    class Foo
    {
        int     memb;
        void    bar();
        ...
    };

    void Foo::bar()
    {
        int * x = memb;        // Needs '&' ?
        int * y = &memb;       // Needs 'Foo::' ?
        int * z = &Foo::memb;  // Okay
    }

Or were you just referring to situations outside of class members
(which require Koenig name lookup)?

Personally, I'm happy that an explicit '&' is required, if that's
now the case.

-- David R. Tribble, dtribble@technologist.com --
---
[ 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: Pete Becker <petebecker@acm.org>
Date: 1998/07/28
Raw View
David R Tribble wrote:
>
>
> Does this mean that the following is (now) illegal?:
>
>     class Foo
>     {
>         int     memb;
>         void    bar();
>         ...
>     };
>
>     void Foo::bar()
>     {
>         int * x = memb;        // Needs '&' ?
>         int * y = &memb;       // Needs 'Foo::' ?
>         int * z = &Foo::memb;  // Okay
>     }
>

The first two have never been legal, except with Microsoft's compiler.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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: Jerry Leichter <leichter@smarts.com>
Date: 1998/07/22
Raw View
| Adding such a thing [if f is a member function, then using it can be
| used syntactically as an "implicit variable"] to C++, without any
| special keywords, would be neigh impossible.  Class.member (without
| the parenthesis) is already a pointer to member function member().

Incorrect.  That's true for non-member functions, but the function-to-
pointer conversion doesn't apply for non-static member functions.  If
you want to generate a pointer-to-member of a member function, an
explicit '&' is required:

  4.3  Function-to-pointer conversion                        [conv.func]

1 An  lvalue  of  function  type T can be converted to an rvalue of type
  "pointer to T."  The result is a pointer to the function.2)

2 [Note: See _over.over_ for additional rules for  the  case  where  the
  function is overloaded.  ]

...
2) This conversion never applies to nonstatic member functions because
  an  lvalue  that  refers  to a nonstatic member function cannot be ob-
  tained.

class.nonstatic-member-function currently has a meaning only (a) just
before an open paren, giving a function call; (b) just after '&'.

(Which is not to say that this addition to the syntax would be a good
idea.  While I really would love to do without all the explicit setter
and getter calls, the delicacy of the proposal - with the meaning of an
expression changing entirely for static vs. non-static member functions
- makes me a bit uncomfortable.  From where I sit, the function-to-
pointer conversion was always a mistake, even in C - personally, I
always write '&' in front of a function name when I want the address, as
it makes the intent so much clearer - but it's got too many years of
history behind it to change now.)
       -- Jerry


[ 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: Pete Becker <petebecker@acm.org>
Date: 1998/07/22
Raw View
David R Tribble wrote:
>
>
> Oops.  I forgot about the fact that naming a function automatically
> decomposes into a pointer to that function.

You didn't forget it, 'cause it ain't so. The only syntax for getting a
pointer to a member is &class::member.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ 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: Pete Becker <petebecker@acm.org>
Date: 1998/07/22
Raw View
AllanW@my-dejanews.com wrote:
>
>
> Adding such a thing to C++, without any special keywords, would
> be neigh impossible.  Class.member (without the parenthesis) is
> already a pointer to member function member().

&Class::member is the only legal way to get a pointer to a member
function. Some compilers are sloppy here.

--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com


[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/07/21
Raw View
David R Tribble wrote:

> This is valuable because if you
> decide to change a variable member into an accessor function
> (which is considered good practice in the realm of data hiding),
> your client code does not need to change (it just needs to be
> recompiled).
>
> Adding such a thing to C++ would be easy to do, since it's a
> semantic change that does not affect the grammar.

I don't follow this last argument.

> It would also have the nice side effect of allowing an accessor
> function to look like an lvalue ('obj.acc = expr') provided
> that the function returns a non-const reference.

Since the goal is to raise the level of encapsulation,
returning a non const reference is the last thing to do.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/07/21
Raw View
Steve Clamage wrote:
>
> zalman@netcom.com (Zalman Stern) writes:
>
> >Another syntactic lack I see is the inability to define something that
> >looks like a data member but that uses setter/getter methods. (E.g. try
> >defining 2D and 3D point classes that derive from a common vector class. To
> >use such classes, one cannot merely write "point.x". One must do something
> >like "point[xCoord]" or "point.x()".
>
> That's a problem inherited from C. Using just the name of a
> function without parens already has a meaning: the address
> of the function. There was no good way to allow it also to
> mean that the function should be called.

The name of a member function applied to an object
has no meaning at all, in C nor in C++:

    point.get_x      no meaning
    &point.get_x     no meaning

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ 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: AllanW@my-dejanews.com
Date: 1998/07/22
Raw View
In article <35B3BC4D.107F@noSPAM.central.beasys.com>,
  dtribble@technologist.com wrote:
> Zalman Stern wrote:
> > Another syntactic lack I see is the inability to define something that
> > looks like a data member but that uses setter/getter methods. (E.g.
> > try defining 2D and 3D point classes that derive from a common vector
> > class. To use such classes, one cannot merely write "point.x". One
> > must do something like "point[xCoord]" or "point.x()".
>
> Eiffel allows such syntactic sugar.  A class member function that
> takes no arguments and a member variable can be accessed using the
> same syntax: 'Class.member'.  This is valuable because if you
> decide to change a variable member into an accessor function
> (which is considered good practice in the realm of data hiding),
> your client code does not need to change (it just needs to be
> recompiled).
>
> Adding such a thing to C++ would be easy to do, since it's a
> semantic change that does not affect the grammar.

Adding such a thing to C++, without any special keywords, would
be neigh impossible.  Class.member (without the parenthesis) is
already a pointer to member function member().

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum


[ 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: zalman@netcom.com (Zalman Stern)
Date: 1998/07/22
Raw View
Valentin Bonnard (bonnardv@pratique.fr) wrote:
: Since the goal is to raise the level of encapsulation,
: returning a non const reference is the last thing to do.

If what you are saying is that it would be much better to have true setter
methods than to have single method that returns a ref, then I agree.

-Z-
---
[ 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: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/22
Raw View
David R Tribble wrote:
>> This is valuable because if you
>> decide to change a variable member into an accessor function
>> (which is considered good practice in the realm of data hiding),
>> your client code does not need to change (it just needs to be
>> recompiled).
>>
>> Adding such a thing to C++ would be easy to do, since it's a
>> semantic change that does not affect the grammar.

Valentin Bonnard wrote:
> I don't follow this last argument.

Oops.  I forgot about the fact that naming a function automatically
decomposes into a pointer to that function.  Personally, I would
prefer that an explicit '&' is required, but oh well, we still
live with some of the inventions/shortcomings of C.

>> It would also have the nice side effect of allowing an accessor
>> function to look like an lvalue ('obj.acc = expr') provided
>> that the function returns a non-const reference.
>
> Since the goal is to raise the level of encapsulation,
> returning a non const reference is the last thing to do.

Yes, that's true.  I don't like returning non-const references
either, as a rule.

So forget I ever proposed such a change.  It would be too big of
a change, however nice it might be.

-- David R. Tribble, dtribble@technologist.com --
---
[ 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: AllanW@my-dejanews.com
Date: 1998/07/22
Raw View
In article <6p03oc$cc0@engnews1.Eng.Sun.COM>,
  stephen.clamage@sun.com (Steve Clamage) wrote:
> zalman@netcom.com (Zalman Stern) writes:
>
> >Another syntactic lack I see is the inability to define something that
> >looks like a data member but that uses setter/getter methods. (E.g. try
> >defining 2D and 3D point classes that derive from a common vector class. To
> >use such classes, one cannot merely write "point.x". One must do something
> >like "point[xCoord]" or "point.x()".
>
> That's a problem inherited from C. Using just the name of a
> function without parens already has a meaning: the address
> of the function. There was no good way to allow it also to
> mean that the function should be called.

I think that I know what Mr. Stern meant.

OO purists remind us that we should never have public data
members.  Even if such members are reasonably well-designed,
making them public locks us into a design scheme -- we can
never change the underlying data types, or calculate them when
needed, because this would break code that is already using
the data members directly.  Using accessor functions, although
still not strictly OO (because we're dealing with individual
attributes instead of actions), at least allows us to change
the internal data structures without breaking any code.

It would be nice if the accessor functions were part of the
language; we would be able to create the illusion of data members
that aren't really there.  I would call these "virtual" data
members, except that "virtual" already has a different
connotation.)  So let's call them "computed" data members, and
please no cracks about COBOL's "COMPUTED" keyword...
Here is an example using invented syntax:

    class distance { public:
        double computed meters;
        double computed inches;
        double computed feet;
        double computed yards;
        double computed miles;
    private:
        double internal;
    };
    double computed meters() const { return internal; }
    double computed meters(double v) { return internal = v; }
    double computed inches() { return internal / 0.0254; }
    double computed inches(double v) { internal = v*0.0254; return v; }
    double computed inches(long v) { internal  = v*0.0254; return v; }
    double computed feet() { return internal / 0.3048; }
    double computed feet(double v) { internal = v*0.3048; return v; }
    double computed yards() { return internal / 0.9144; }
    double computed yards(double v) { internal = v*0.9144; return v; }
    double computed miles() { return internal / 1609.344; }
    double computed miles(double v) { internal = v*1609.344; return v; }

The overloaded inches(long) is there to demonstrate that the
accessor functions can also handle specialized conversion,
although this case was not neccesary (the long would be promoted
to double automatically anyway).

You would be able to use the computed data members in every way that
a normal data member can be used, except that you cannot take it's
address or point a reference at it.

    #include <iostream>
    #include "distance.h"
    int main(int,char*[]) {
        std::cout << "Enter the number of miles: ";
        double d;
        std::cin >> d;
        distance dist;
        dist.miles = d;
        std::cout
            << dist.miles  << " miles, "
            << dist.meters << " meters, "
            << dist.yards  << " yards, "
            << dist.feet   << " feet, "
            << dist.inches << " inches" << std::endl;
        return 0;
    }

Note that class double could have made meters a "real" data member,
instead of using internal for this purpose, with no changes to main().
But this would be bad design, because there wouldn't be anything to
stop the application from taking the address of meters, perhaps
without realizing it as in:
    std::cin >> dist.meters; // This would be a problem
ostream's operator>> accepts a reference to double for it's second
argument.  This means that the double has to have real memory with a
real address.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: zalman@netcom.com (Zalman Stern)
Date: 1998/07/20
Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:
: You already have that capability: You can write any function you
: like that makes use only of the public interface. The only
: difference from what you have suggested is a minor difference in
: syntax:  Instead of declaring and calling the function like this:
:  String String::left(int);
:  s.left(4)
: you declare and call it like this:
:  String left(String&, int);
:  left(s, 4);

Syntax is a big deal when implementing and using templates. Especially when
designing components that work well with a set of templates and provide a
pleasant interface for direct programmer use. For example. it is
syntactically a fair bit more hassle to declare function objects
(especially if the don't inherit from the unary or binary function classes)
than to declare a simple function.

I find this to be a lack of expressiveness in the language. (Which is not
to say, anything negative about the standard, just that I think template
facillities will motivate more "syntactic power" being added to C++ in the
future. Note that "syntactic" implies that such additions won't necessarily
make the language do more, merely make it easier to use.)

Another syntactic lack I see is the inability to define something that
looks like a data member but that uses setter/getter methods. (E.g. try
defining 2D and 3D point classes that derive from a common vector class. To
use such classes, one cannot merely write "point.x". One must do something
like "point[xCoord]" or "point.x()".

-Z-


[ 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: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/07/21
Raw View
Zalman Stern wrote:
> Another syntactic lack I see is the inability to define something that
> looks like a data member but that uses setter/getter methods. (E.g.
> try defining 2D and 3D point classes that derive from a common vector
> class. To use such classes, one cannot merely write "point.x". One
> must do something like "point[xCoord]" or "point.x()".

Eiffel allows such syntactic sugar.  A class member function that
takes no arguments and a member variable can be accessed using the
same syntax: 'Class.member'.  This is valuable because if you
decide to change a variable member into an accessor function
(which is considered good practice in the realm of data hiding),
your client code does not need to change (it just needs to be
recompiled).

Adding such a thing to C++ would be easy to do, since it's a
semantic change that does not affect the grammar.

It would also have the nice side effect of allowing an accessor
function to look like an lvalue ('obj.acc = expr') provided
that the function returns a non-const reference.  This sort of
thing makes the intention of assignment more obvious than the
equivalent 'obj.acc(expr)' or 'obj.setAcc(expr)'.


-- David R. Tribble, dtribble@technologist.com --
-- C++, the PL/1 of the 90s.


[ 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: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/07/21
Raw View
zalman@netcom.com (Zalman Stern) writes:


>Another syntactic lack I see is the inability to define something that
>looks like a data member but that uses setter/getter methods. (E.g. try
>defining 2D and 3D point classes that derive from a common vector class. To
>use such classes, one cannot merely write "point.x". One must do something
>like "point[xCoord]" or "point.x()".

That's a problem inherited from C. Using just the name of a
function without parens already has a meaning: the address
of the function. There was no good way to allow it also to
mean that the function should be called.

--
Steve Clamage, stephen.clamage@sun.com


[ 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: Tim Ottinger <ottinger@oma.com>
Date: 1998/07/18
Raw View
I swear this is not intended as a troll.

You can add members on the fly if you don't use a statically-typed language,
or if you can come up with a way to neatly support roles in C++ (which I
want when you're done).

In dynamically-typed languages, messages are looked-up by name in a
real method dispatch table, which adds lots of overhead compared to
C++s and Eiffel's versions of vtable. It's reasonable that all *overloadable*
functions occupy a known place in the vtable of a class.

Now if we could add statically-bound methods with the appropriate
syntactic sugar, then roles and improvements in template use would
follow suit. In such a limited situation, and within the rules of dis-
ambiguation, I'd *love* to see such a thing added to the language.

Maybe next go 'round?


Valentin Bonnard wrote:

> Alex Jonas <ajonas@altavista.net> writes:
>
> > I have always felt that it would be useful to be able to define
> > (non virtual public, non data) member functions of a class outside the
> > class itself. For example:
> >
> > class String
> > {
> >   //....
> >   // no member String left(int) defined here
> >   //...
> > };
> >
> > String String::left(int chars); // Defined outside the class
> >
> > I can think of a number of benefits:
>
> Wonderfull ! I am not alone.
>
> > It would obviously make sense for the methods declared externally to be
> > public and to have access only to public data.
> >
> > I believe that this feature is not part of the standard, and is not intended
> > to be. Is this correct? Also, what are the problems associated with it? Any
> > comments are welcome.
>
> The way I see it is that we should ban member functions. Then
> put back member functions as:
> - syntaxic suggar
> - backward compatibillity
> - and to annoy OO purists
>
> You can see my article in comp.lang.c++.moderated:
>
> http://www.dejanews.com/dnquery.xp?QRY=Banning+member+functions+%28Was
> %3A+Guru+of+the+Week%29&ST=PS&DBS=1&defaultOp=AND&groups=comp.lang.c%2B
> %2B.moderated
>
> I call that non-member member functions.
>
> --
>
> Valentin Bonnard                mailto:bonnardv@pratique.fr
> info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
>
> [ 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              ]
---
[ 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: "Alex Jonas" <ajonas@altavista.net>
Date: 1998/07/15
Raw View
Steve Clamage wrote in message <6oeppc$sa2@engnews1.Eng.Sun.COM>...
>"Alex Jonas" <ajonas@altavista.net> writes:
>
>>I have always felt that it would be useful to be able to define
>>(non virtual public, non data) member functions of a class outside the
>>class itself.
>
>>[snip]
>

>One important property of a class is that every function that
>has access to non-public members is declared in the class.
>
>
>>It would obviously make sense for the methods declared externally to be
>>public and to have access only to public data.
>
>You already have that capability: You can write any function you
>like that makes use only of the public interface. The only
>difference from what you have suggested is a minor difference in
>syntax:  Instead of declaring and calling the function like this:
> String String::left(int);
> s.left(4)
>you declare and call it like this:
> String left(String&, int);
> left(s, 4);


It is precicely this minor difference in syntax that causes the problems. In
an
isolated case where a programmer is simply writing code, it isn't a problem
as
the programmer can, on the spot, call left(s, 4) instead of s.left(4). But
what if the
call to s.left(4) is in a template method of a third party library, and s is
also a third
party class. You may be able to specialize the template, but this could get
ugly.
You could derive MyString from String and add the left method but this
causes problems.
eg. A vector<String> is not compatible with vector<MyString>. Not to mention
the fact that
the left method has access to protected members of String. You could make
MyString take
a pointer to a string and forward the required calls. This also causes
vector<String> to be
incompatible with vector<MyString>.

Now, quite often, a template method/class is designed such that the class
with which it is
instanciated has to fullfill a concept. Say, ForwardIterator etc. I may have
a class that fullfills
the concept, but does not match the names of methods called by the template
exactly.
I seem to have no satisfactory way of adapting my class to fit the template.

Let me give an example of where an idea like this is currently in use.
iostreams.

If I write:

cout << x;

It could be interpreted as
cout.operator<<(x);
or
operator<<(cout, x);
depending on the type of x.

Say, for instance, iostreams were to use a member function instead of an
operator.

class ostream : ...
{
public:
  ostream& out(int);
};

Then the following code would be acceptable (and would remove ambiguities
between
<< and other operators)

cout.out(5).out(6).out(7);

Unfortunately, if we wanted to output classes of our own,
we would have to impose a different syntax on the user
(or pray that iostreams had a template member that we could specialize).

int x; MyClass c;

out(cout.out(x), c);

If we were simply allowed to declare

ostream& ostream::out(const MyClass& c);

ouside of ostream, then everything would be fine. Note also,
that even though it would be logically an extension of ostream, it
could be packaged with MyClass. Thus the only dependants on
a change to ostream& ostream::out(const MyClass& c) are users
of MyClass and not all users of ostream.

-

Alex Jonas
---
[ 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: AllanW@my-dejanews.com
Date: 1998/07/15
Raw View
In article <35aa3a87.0@newsread1.dircon.co.uk>,
  "Alex Jonas" <ajonas@altavista.net> wrote:
> I have always felt that it would be useful to be able to define
> (non virtual public, non data) member functions of a class outside the
> class itself. For example:
>
> class String
> {
>   //....
>   // no member String left(int) defined here
>   //...
> };
>
> String String::left(int chars); // Defined outside the class

You can already do the equivalent of this, albeit with slightly
different syntax.
    String left(String s, int chars);
Instead of calling this with
    str.left(5)
you would use
    left(str,5)

> I can think of a number of benefits:
>
> 1) Extending a class from a third party or from the STL.
You can do this by writing (possibly overloaded) functions which
use third-party class types as a parameter.

> I am allowed to derive from a class but this causes problems. Even after
> use of conversion operators to ensure compatibility with my derived class,
> container classes are no longer compatible.
> eg. vector<string>, vector<MyString>
In this case, deriving a class simply to add additional functionality
might be less than ideal.  Use global functions instead.

>
> 2) I could write a template member that could be applied to any class
> template <class T, class V>
> void T::fill_all(const V&v) {fill(begin(), end(), v);}
How about
    template<class T, class V>fill_all(T&t, const V&v)
        { fill(t.begin(), t.end(), v); }

> Allowing
>
> vector<int> x(50);
> x.fill_all(100);
>
> string s;
> s.fill_all('a');
My version allows
    vector<int> x(50);
    fill_all(x,100);
    string s;
    fill_all(s,'a');

> 3) I could separate out essential members from convenience methods,
> splitting my class into two or more separate files allowing for
> more intelligent rebuilds.
Not sure what this distinction is; I'm guessing that "convenience
methods" are methods that can be 100% defined in terms of public
members, and "essential members" are everything else.  But does
one of these groups tend to change more often than the other?

Even if your answer is yes, you still have two choices.  Declare your
"convenience methods" as public member functions, or declare them as
global functions accepting a T argument.  Either way, you can move
the actual definitions into any source file you like.

> 4) It makes it easier for two separate third parties to extend classes from
> the STL (or other) while retaining compatibility with each other.
No easier than global functions.  See, for instance, any of the STL
"algorithm" functions, none of which are member functions.

> 5) I could make my class or a third party class compatible with an existing
> template
> function/method without unnecessarily polluting the class definition.
Another good argument for global functions.

> It would obviously make sense for the methods declared externally to be
> public and to have access only to public data.
All of which are available to global functions.  It would also have to
be non-virtual.

> I believe that this feature is not part of the standard, and is not intended
> to be. Is this correct?
That's my understanding as well.

> Also, what are the problems associated with it? Any
> comments are welcome.
I'm not sure if there are any major problems with it, except for the
fact that a class definition wouldn't be all in one place.  This might
make certain compiler optimizations much more difficult.  However,
there is really no need for it.

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp   Create Your Own Free Member Forum
---
[ 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: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/07/16
Raw View
Alex Jonas <ajonas@altavista.net> writes:

> I have always felt that it would be useful to be able to define
> (non virtual public, non data) member functions of a class outside the
> class itself. For example:
>
> class String
> {
>   //....
>   // no member String left(int) defined here
>   //...
> };
>
> String String::left(int chars); // Defined outside the class
>
> I can think of a number of benefits:

Wonderfull ! I am not alone.

> It would obviously make sense for the methods declared externally to be
> public and to have access only to public data.
>
> I believe that this feature is not part of the standard, and is not intended
> to be. Is this correct? Also, what are the problems associated with it? Any
> comments are welcome.

The way I see it is that we should ban member functions. Then
put back member functions as:
- syntaxic suggar
- backward compatibillity
- and to annoy OO purists

You can see my article in comp.lang.c++.moderated:

http://www.dejanews.com/dnquery.xp?QRY=Banning+member+functions+%28Was
%3A+Guru+of+the+Week%29&ST=PS&DBS=1&defaultOp=AND&groups=comp.lang.c%2B
%2B.moderated

I call that non-member member functions.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ 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: "Alex Jonas" <ajonas@altavista.net>
Date: 1998/07/13
Raw View
I have always felt that it would be useful to be able to define
(non virtual public, non data) member functions of a class outside the
class itself. For example:

class String
{
  //....
  // no member String left(int) defined here
  //...
};

String String::left(int chars); // Defined outside the class

I can think of a number of benefits:

1) Extending a class from a third party or from the STL.
I am allowed to derive from a class but this causes problems. Even after
use of conversion operators to ensure compatibility with my derived class,
container classes are no longer compatible.
eg. vector<string>, vector<MyString>

2) I could write a template member that could be applied to any class
template <class T, class V>
void T::fill_all(const V&v) {fill(begin(), end(), v);}

Allowing

vector<int> x(50);
x.fill_all(100);

string s;
s.fill_all('a');

3) I could separate out essential members from convenience methods,
splitting my class into two or more separate files allowing for
more intelligent rebuilds.

4) It makes it easier for two separate third parties to extend classes from
the STL (or other) while retaining compatibility with each other.

5) I could make my class or a third party class compatible with an existing
template
function/method without unnecessarily polluting the class definition.

------------------------------

It would obviously make sense for the methods declared externally to be
public and to have access only to public data.

I believe that this feature is not part of the standard, and is not intended
to be. Is this correct? Also, what are the problems associated with it? Any
comments are welcome.

TIA
Alex Jonas
---
[ 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: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/07/14
Raw View
"Alex Jonas" <ajonas@altavista.net> writes:

>I have always felt that it would be useful to be able to define
>(non virtual public, non data) member functions of a class outside the
>class itself. For example:

>class String
>{
>  //....
>  // no member String left(int) defined here
>  //...
>};

>String String::left(int chars); // Defined outside the class

One important property of a class is that every function that
has access to non-public members is declared in the class. If
that were not the case, you could never change any part of
a class without breaking programs you don't know about; any
program might have inserted its own member functions that
depended on implementation details.

If you don't own the class, you can't write anything that depends
on private implementation details. The owner of the class is free
to make implementation changes that don't alter the public interface
and be sure that the changes won't break your program.

>------------------------------

>It would obviously make sense for the methods declared externally to be
>public and to have access only to public data.

You already have that capability: You can write any function you
like that makes use only of the public interface. The only
difference from what you have suggested is a minor difference in
syntax:  Instead of declaring and calling the function like this:
 String String::left(int);
 s.left(4)
you declare and call it like this:
 String left(String&, int);
 left(s, 4);

--
Steve Clamage, stephen.clamage@sun.com
---
[ 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: "Martijn Lievaart" <Invalid@against.spam.nl>
Date: 1998/07/14
Raw View
Alex Jonas wrote in message <35aa3a87.0@newsread1.dircon.co.uk>...
>I have always felt that it would be useful to be able to define
>(non virtual public, non data) member functions of a class outside the
>class itself. For example:
>
>class String
>{
>  //....
>  // no member String left(int) defined here
>  //...
>};
>
>String String::left(int chars); // Defined outside the class
>
(snip)
>
>I believe that this feature is not part of the standard, and is not
intended
>to be. Is this correct? Also, what are the problems associated with it? Any
>comments are welcome.
>

Think about this:

file1.h
#include <string.h>    // include definition of String class

inline String String::left(int chars) // Defined outside the class
{
    // some implementation: return substring of this without modifying this
}


file2.h
#include <string.h>    // include definition of String class
inline String String::left(int chars) // Defined outside the class
{
    // some completely other implementation:
    // set this to substring and return this
}

This would create a complete mess as the implementation of the function
would depend on the header file you included. (Ofcourse this is contrived as
the first implementation should be const, but the idea is valid)

Note that template specialization can create the same mess if one
translation unit sees the specialization while another does not, but I gues
the linker would complain. I haven't tried this yet. Comments anyone?

Greetz,
Martijn (see sig for email address)
--
#include <stddisclaimer.h>
My email address is intentionally invalid agains spam.
Please reply to mlievaar at orion in nl





[ 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: "Alex Jonas" <ajonas@altavista.net>
Date: 1998/07/14
Raw View
Martijn Lievaart wrote in message <6ofmse$t8g@news3.euro.net>...
>Alex Jonas wrote in message <35aa3a87.0@newsread1.dircon.co.uk>...
>>I have always felt that it would be useful to be able to define
>>(non virtual public, non data) member functions of a class outside the
>>class itself.
>>
>
>Think about this:
>
>file1.h
>#include <string.h>    // include definition of String class
>inline String String::left(int chars) // Defined outside the class
>{
>    // some implementation: return substring of this without modifying this
>}
>
>
>file2.h
>#include <string.h>    // include definition of String class
>inline String String::left(int chars) // Defined outside the class
>{
>    // some completely other implementation:
>    // set this to substring and return this
>}
>

>This would create a complete mess as the implementation of the function
>would depend on the header file you included. (Ofcourse this is contrived
>as the first implementation should be const, but the idea is valid)


The example fails because it violates the "one definition rule" (ODR).
Declaring left in String is no protection against this. So wether or not
left is declared inside or outside String you can trip yourself up in the
above manner.

--

Alex Jonas








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