Topic: Multiple dispatch


Author: "Sylvester Hesp" <s.hesp@oisyn.nl>
Date: Thu, 12 Apr 2007 11:19:55 CST
Raw View
"jam" <farid.mehrabi@gmail.com> wrote in message
news:1174339506.501270.266070@e65g2000hsc.googlegroups.com...
>
> On Mar 19, 10:05 pm, "Grizlyk" <grizl...@yandex.ru> wrote:
>
>> Also why have you called this stuff as "multiple dispath"? It looks
>> like special implemetation of "single dispatch" with "type of class"
>> as single dispatch selector.
>>
>> As i know multiple dispatch is something, that has other dispath
>> selectors, in addition to "class of object", for example, first
>> parametter of function can be second dispatch selector.
>>
> I call that a normal overloading. Different name mangling is exerted on
> functions with different params but that is not curently the case for
> functions with same name and prototype which leads in a complete
> hiding behavoir. Note that we expect different behavoir when calling
> 'go' from an 'A'  or a 'D' pointer/reference.So correct dispaching
> will be important.

Yet your example is still single dispatch, and you probably misunderstood
Maksim. The only dispatching selector involved is the class instance pointer
you use to call the function upon. Multiple dispatch is when you use more
than one selector (not available in C++98 but perhaps in C++0x).
Example of single dispatch:

struct Base { virtual void foo(); }
struct Derived : public Base { void foo(); };

Base * b = new Derived();
b->foo();  // calls Derived::foo

The above uses single dispatch because it only dispatches on one parameter:
the 'b' pointer. Whether the vtable entry for foo() points to a method of a
class that is overloaded for several base classes doesn't make it multi
dispatch. There is only 1 dispatch parameter.


Example of multi dispatch (using syntax from the n2216 proposal):

void bar(virtual Base * a, virtual Base * b);
void bar(virtual Base * a, virtual Derived * b);
void bar(virtual Derived * a, virtual Derived * b);
void bar(virtual Derived * a, virtual Derived * b);

// the following calls are all multi dispatch - they use both parameters to
select the appropriate overloaded function at runtime
// note that the compiletime-type of both 'b' and 'd' is Base*
Base *b = new Base(), *d = new Derived();
bar(b, b);  // calls bar(Base*, Base*)
bar(b, d);  // calls bar(Base*, Derived*)
bar(d, b);  // calls bar(Derived*, Base*)
bar(d, d);  // calls bar(Derived*, Derived*)

Of course this is 'overloading' because bar is overloaded, but it is also
multi-dispatch because the runtime-types of both parameters are used to
select the right function. That makes the call to bar multiple dispatch

More information is in n2216
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf)


- Sylvester Hesp


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "jam" <farid.mehrabi@gmail.com>
Date: Mon, 19 Mar 2007 23:02:29 CST
Raw View
===================================== MODERATOR'S COMMENT:
 Please remove excessive quoting when replying.


===================================== END OF MODERATOR'S COMMENT
On Mar 19, 10:05 pm, "Grizlyk" <grizl...@yandex.ru> wrote:
> jam wrote:
>
> > struct A{
> >  virtual void go();
> > };
>
> > struct B{
> >  virtual void go();
> > };
>
> > struct C{
> >  virtual void go();
> > };
>
> > struct D{
> >  virtual void go();
> > };
>
> > if a class inherits any two of the above then it will have to define
> > its own version of go that will replace in both vtables inherited.
> > Here is a humble syntax proposal:
>
> > struct all: A,B,C,D{
> >    // here is the syntax:
> >    void go() A{cout<<'A';};//override A::go
> >    void go() B{cout<<'B';};//override B::go
> >    void go(){cout<<"all";};//used for C,D and all
>
> > };
>
> > all * ptr=new all;
>
> > ptr->go();//prints 'all'
> > ((A*)ptr)->go();//prints 'A'
> > ((B*)ptr)->go();//prints 'B'
> > ((C*)ptr)->go();//prints 'all'
> > ((D*)ptr)->go();//prints 'all'
>
> > vtables of A and B got different versions of go than C and D and if
> > any class inherits 'struct all' then by default it will use theversoin
> > of go that prints 'all' unless it is casted to A or be or redefines
> > go.
>
> Probably it can be done, but for
>
> >    void go(){cout<<"all";};  //used for C,D and all
>
> you will need entry in vtable of struct "all" for "all::go()", that
> normally can be avoided (any vtable of base class can be used to find
> "(all*)(ptr)->go();" ).

the order by which the types are phsically inherited is even currently
affected by polymorphic bases. On VC7 the first subobject is the first
polymorphic subobject if there is any.So either C or D could be placed
at the beginning by the compiler .In special cases where all
subobjects have distinct overrides of their own (that is A,B,C and D
each have a specialized vesoin of 'go' ) introducing a general
override(the one printing 'all' in the above example would necessitate
an extra vtable.

>
> But what the practical puprose of the kind of separatedly overloaded
> base methods? I do not see any.
>

suppose 'all' is inheriting from multiple classes defined in different
libraries having functions with similar names and signatures but
different purposes.You can not specify one override for both because
they have different goals and accidentally same names.This becomes a
major problem specially when trying to model C# and JAVA interfaces as
abstract claases containing abstract functions;Now what happens if two
or more of such interface-ish abstract bases have a function with same
name and prototype(as you know interfaces - in contrast to classes -
are multiply inherited in C# and java and the implementing class
defines them as members of the deffining interface)?

> Also why have you called this stuff as "multiple dispath"? It looks
> like special implemetation of "single dispatch" with "type of class"
> as single dispatch selector.
>
> As i know multiple dispatch is something, that has other dispath
> selectors, in addition to "class of object", for example, first
> parametter of function can be second dispatch selector.
>
I call that a normal overloading.Different name mangling is exerted on
functions with different params but that is not curently the case for
functions with same name and prototype which leads in a complete
hiding behavoir. Note that we expect different behavoir when calling
'go' from an 'A'  or a 'D' pointer/reference.So correct dispaching
will be important.
> struct Base
> {
>     virtual void foo(const Base&)=0;
>
> };
>
> struct Derived: public Base
> {
>     void foo(const Base&);
>     dispatched void foo(const Derived&);
>     dispatched void foo(const int);
>
> };
>
> struct Extra: public Derived
> {
>     void foo(const double);
>
> };
>
> Here all "foo" with only one parameter became "dispatched" for class
> Derived and for all classes inherited from Derived.
>
> extern Base auto*  param;
> Base heap*  ptr=new Derived;
>
> void   foo()
> {
>     ptr->foo(*param);
>
> }
>
> Here "Derived::foo(const Base&)" will be called if
> "typeid(*param)==typeid(Base)" and "Derived::foo(const Derived&)" will
> be called if "typeid(*param)==typeid(Derived)".
>
> It looks like
>
>    Base::vtbl[foo_offset](*param);
>
> here called C++ generated
>     Derived::virtual_to_dispatcher( param );
>
> void Derived::virtual_to_dispatcher( param )
> {
>     Derived::dispatcher_foo( typeid(param), param );
>
> }
>
> here called C++ generated
>     Derived::dispatcher_foo( typeid(param), param )
>
> void Derived::dispatcher_foo( const typeid& id, ... )
> {
> va_list param;
>     va_start(param, id);
>
>     if( id == typeid(const int) )
>      {
>       const int   tmp=va_arg(param,const int);
>       va_end(param);
>       [return] Derived::foo( (const int)param );
>       [return;]
>      }
>
>     if( id == typeid(Derived) )
>      {
>       Derived&   tmp=va_arg(param,Derived&);
>       va_end(param);
>       [return] Derived::foo( (Derived&)param );
>       [return;]
>      }
>
>     //if( id == typeid(Base) )
>      {
>       Base&   tmp=va_arg(param,Base&);
>       va_end(param);
>       [return] Derived::foo( (Base&)param );
>       [return;]
>      }
>
>     //execution control never reach the point
>     //due to static type checking
>
> }
>
> void   boo()
> {
> Base    b;
> Derived d;
> Extra    e;
>
>     b.foo(*ptr);
>     b.foo(b);
>     b.foo(d);
>     b.foo(e);
>
>     d.foo(*ptr);
>     d.foo(b);
>     d.foo(d);
>     d.foo(e);
>     d.foo(100);
>
>     e.foo(*ptr);
>     e.foo(b);
>     e.foo(d);
>     e.foo(100);
>     e.foo(0.1);
>
> }
>
> Of course, multiple dispatching is doing by the cost of perfomans
> lost.
>
> --
> Maksim A. Polyaninhttp://grizlyk1.narod.ru/cpp_new
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-...@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ:http://www.comeaucomputing.com/csc/faq.html                     ]- Hide quoted text -
>
> - Show quoted text -


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "jam" <farid.mehrabi@gmail.com>
Date: Mon, 19 Mar 2007 11:44:09 CST
Raw View
On Mar 13, 9:48 pm, "frege" <gottlobfr...@gmail.com> wrote:
> On Mar 9, 6:24 pm, "jam" <farid.mehr...@gmail.com> wrote:
>
>
>
>
>
> > consider:
>
> > struct A{
> >  virtual void go();
>
> > };
>
> > struct B{
> >  virtual void go();
>
> > };
>
> > struct C{
> >  virtual void go();
>
> > };
>
> > struct D{
> >  virtual void go();
>
> > };
>
> > if a class inherits any two of the above then it will have to define
> > its own version of go that will replace in both vtables inherited.
> > Here is a humble syntax proposal:
>
> > struct all: A,B,C,D{
> >    // here is the syntax:
> >    void go() A{cout<<'A';};//override A::go
> >    void go() B{cout<<'B';};//override B::go
> >    void go(){cout<<"all";};//used for C,D and all
>
> > };
>
> How about
> struct all : A,B,C,D {
>    void A::go() { cout << 'A' };
>    void B::go() { cout << 'B' };
>    void C::go() { cout << 'C' };
>    void D::go() { all::C::go(); };
>
> };
>
> some of which MS Visual C++ already supports  (ie it supports adding
> the base class to the declaration of a virtual member function - ie
> 'Base::func()'.  And it will complain if 'func' is not a member of
> Base, which catches some coding errors.)
>
>
> - Show quoted text -

use of scope resolution operator (::) makes the syntax in-consistent
and confusing more over you are forwarding 'C' version of 'go' inside
that of 'D' that for more complex functions - accepting parameters and
returning reslt - generate unnecessary overheads.see:

http://groups.google.com/group/comp.std.c++/browse_frm/thread/5f0ebaafb1205209/?hl=en#

we currently can write:

void a_class::a_function() const //as if this is const
{/*and so on*/};

I humblly propose that we can write:

struct all: A,B,C,D {
   // here is the syntax:
   void go() A // as if this is an A
          {cout<<'A';};//override A::go

   void go() B // as if this is a B
          {cout<<'B';};//override B::go

   void go()  //this is netiher  A nor B
          {cout<<"all";};//used for C,D and all
};

which is consistent with current semantics.Moreover this is intended
to be a standard platform independent feature .

regards
FM

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Grizlyk" <grizlyk1@yandex.ru>
Date: Mon, 19 Mar 2007 12:05:39 CST
Raw View
jam wrote:
>
> struct A{
>  virtual void go();
> };
>
> struct B{
>  virtual void go();
> };
>
> struct C{
>  virtual void go();
> };
>
> struct D{
>  virtual void go();
> };
>
> if a class inherits any two of the above then it will have to define
> its own version of go that will replace in both vtables inherited.
> Here is a humble syntax proposal:
>
> struct all: A,B,C,D{
>    // here is the syntax:
>    void go() A{cout<<'A';};//override A::go
>    void go() B{cout<<'B';};//override B::go
>    void go(){cout<<"all";};//used for C,D and all
>
> };
>
> all * ptr=new all;
>
> ptr->go();//prints 'all'
> ((A*)ptr)->go();//prints 'A'
> ((B*)ptr)->go();//prints 'B'
> ((C*)ptr)->go();//prints 'all'
> ((D*)ptr)->go();//prints 'all'
>
> vtables of A and B got different versions of go than C and D and if
> any class inherits 'struct all' then by default it will use theversoin
> of go that prints 'all' unless it is casted to A or be or redefines
> go.

Probably it can be done, but for

>    void go(){cout<<"all";};  //used for C,D and all

you will need entry in vtable of struct "all" for "all::go()", that
normally can be avoided (any vtable of base class can be used to find
"(all*)(ptr)->go();" ).

But what the practical puprose of the kind of separatedly overloaded
base methods? I do not see any.

Also why have you called this stuff as "multiple dispath"? It looks
like special implemetation of "single dispatch" with "type of class"
as single dispatch selector.

As i know multiple dispatch is something, that has other dispath
selectors, in addition to "class of object", for example, first
parametter of function can be second dispatch selector.

struct Base
{
    virtual void foo(const Base&)=0;
};

struct Derived: public Base
{
    void foo(const Base&);
    dispatched void foo(const Derived&);
    dispatched void foo(const int);
};

struct Extra: public Derived
{
    void foo(const double);
};

Here all "foo" with only one parameter became "dispatched" for class
Derived and for all classes inherited from Derived.

extern Base auto*  param;
Base heap*  ptr=new Derived;

void   foo()
{
    ptr->foo(*param);
}

Here "Derived::foo(const Base&)" will be called if
"typeid(*param)==typeid(Base)" and "Derived::foo(const Derived&)" will
be called if "typeid(*param)==typeid(Derived)".

It looks like

   Base::vtbl[foo_offset](*param);

here called C++ generated
    Derived::virtual_to_dispatcher( param );

void Derived::virtual_to_dispatcher( param )
{
    Derived::dispatcher_foo( typeid(param), param );
}

here called C++ generated
    Derived::dispatcher_foo( typeid(param), param )

void Derived::dispatcher_foo( const typeid& id, ... )
{
va_list param;
    va_start(param, id);

    if( id == typeid(const int) )
     {
      const int   tmp=va_arg(param,const int);
      va_end(param);
      [return] Derived::foo( (const int)param );
      [return;]
     }

    if( id == typeid(Derived) )
     {
      Derived&   tmp=va_arg(param,Derived&);
      va_end(param);
      [return] Derived::foo( (Derived&)param );
      [return;]
     }

    //if( id == typeid(Base) )
     {
      Base&   tmp=va_arg(param,Base&);
      va_end(param);
      [return] Derived::foo( (Base&)param );
      [return;]
     }

    //execution control never reach the point
    //due to static type checking
}

void   boo()
{
Base    b;
Derived d;
Extra    e;

    b.foo(*ptr);
    b.foo(b);
    b.foo(d);
    b.foo(e);

    d.foo(*ptr);
    d.foo(b);
    d.foo(d);
    d.foo(e);
    d.foo(100);

    e.foo(*ptr);
    e.foo(b);
    e.foo(d);
    e.foo(100);
    e.foo(0.1);
}

Of course, multiple dispatching is doing by the cost of perfomans
lost.

--
Maksim A. Polyanin
http://grizlyk1.narod.ru/cpp_new

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "jam" <farid.mehrabi@gmail.com>
Date: Wed, 14 Mar 2007 16:08:00 CST
Raw View
On Mar 11, 12:06  am, godwa...@gmail.com wrote:
> On 3   10   ,       7   24   , "jam" <farid.mehr...@gmail.com> wrote:
>
>
>
>
>
> > consider:
>
> > struct A{
> >   virtual void go();
>
> > };
>
> > struct B{
> >   virtual void go();
>
> > };
>
> > struct C{
> >   virtual void go();
>
> > };
>
> > struct D{
> >   virtual void go();
>
> > };
>
> > if a class inherits any two of the above then it will have to define
> > its own version of go that will replace in both vtables inherited.
> > Here is a humble syntax proposal:
>
> > struct all: A,B,C,D{
> >      // here is the syntax:
> >      void go() A{cout<<'A';};//override A::go
> >      void go() B{cout<<'B';};//override B::go
> >      void go(){cout<<"all";};//used for C,D and all
>
> > };
>
> I think we can use the following instead:
>
> struct AA : A{
>      virtual void go() {cout<<'B';}
>
> };
>
> struct BB : B{
>      virtual void go() {cout<<'A';}
>
> };
>
> struct CD : C, D{
>      virtual void go() {cout<<'all';}
>
> };
>
> struct all: AA,BB,CD{
>
> };
>
> I think it's enough for this usage.
>
This feature is to be inheritable but your solution is NOT.what if one
needs to inherit from 'all' n a way that  it can produce specialized
versions of virtual functions for A,B,C and D?


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "jam" <farid.mehrabi@gmail.com>
Date: Wed, 14 Mar 2007 16:24:59 CST
Raw View
On Mar 13, 9:48 pm, "frege" <gottlobfr...@gmail.com> wrote:
> On Mar 9, 6:24 pm, "jam" <farid.mehr...@gmail.com> wrote:
>
>
>
>
>
> > consider:
>
> > struct A{
> >  virtual void go();
>
> > };
>
> > struct B{
> >  virtual void go();
>
> > };
>
> > struct C{
> >  virtual void go();
>
> > };
>
> > struct D{
> >  virtual void go();
>
> > };
>
> > if a class inherits any two of the above then it will have to define
> > its own version of go that will replace in both vtables inherited.
> > Here is a humble syntax proposal:
>
> > struct all: A,B,C,D{
> >    // here is the syntax:
> >    void go() A{cout<<'A';};//override A::go
> >    void go() B{cout<<'B';};//override B::go
> >    void go(){cout<<"all";};//used for C,D and all
>
> > };
>
> How about
> struct all : A,B,C,D {
>    void A::go() { cout << 'A' };
>    void B::go() { cout << 'B' };
>    void C::go() { cout << 'C' };
>    void D::go() { all::C::go(); };
>
> };
>
> some of which MS Visual C++ already supports  (ie it supports adding
> the base class to the declaration of a virtual member function - ie
> 'Base::func()'.  And it will complain if 'func' is not a member of
> Base, which catches some coding errors.)
>
>
> - Show quoted text -

use of scope resolution operator (::) makes the syntax in-consistent
and confusing more over you are forwarding 'C' version of 'go' inside
that of 'D' that for more complex functions - accepting parameters and
returning reslt - generate unnecessary overheads.see:

http://groups.google.com/group/comp.std.c++/browse_frm/thread/5f0ebaafb1205209/?hl=en#

we currently can write:

void a_class::a_function() const{/*and so on*/};

I humblly propose that we can write:

struct all: A,B,C,D {
   // here is the syntax:
   void go() A // as if this is an A
          {cout<<'A';};//override A::go

   void go() B // as if this is a B
          {cout<<'B';};//override B::go

   void go()  //this is netiher  A nor B
          {cout<<"all";};//used for C,D and all
};

which is consistent with current semantics.Moreover this is intended
to be a standard platform independent feature .


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "jam" <farid.mehrabi@gmail.com>
Date: Fri, 9 Mar 2007 17:24:56 CST
Raw View
consider:

struct A{
 virtual void go();
};

struct B{
 virtual void go();
};

struct C{
 virtual void go();
};

struct D{
 virtual void go();
};

if a class inherits any two of the above then it will have to define
its own version of go that will replace in both vtables inherited.
Here is a humble syntax proposal:

struct all: A,B,C,D{
   // here is the syntax:
   void go() A{cout<<'A';};//override A::go
   void go() B{cout<<'B';};//override B::go
   void go(){cout<<"all";};//used for C,D and all
};

all * ptr=new all;

ptr->go();//prints 'all'
((A*)ptr)->go();//prints 'A'
((B*)ptr)->go();//prints 'B'
((C*)ptr)->go();//prints 'all'
((D*)ptr)->go();//prints 'all'

vtables of A and B got different versions of go than C and D and if
any class inherits 'struct all' then by default it will use theversoin
of go that prints 'all' unless it is casted to A or be or redefines
go.

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: godwater@gmail.com
Date: Sat, 10 Mar 2007 14:06:28 CST
Raw View
On 3      10      ,             7  24      , "jam" <farid.mehr...@gmail.com> wrote:
> consider:
>
> struct A{
>  virtual void go();
>
> };
>
> struct B{
>  virtual void go();
>
> };
>
> struct C{
>  virtual void go();
>
> };
>
> struct D{
>  virtual void go();
>
> };
>
> if a class inherits any two of the above then it will have to define
> its own version of go that will replace in both vtables inherited.
> Here is a humble syntax proposal:
>
> struct all: A,B,C,D{
>    // here is the syntax:
>    void go() A{cout<<'A';};//override A::go
>    void go() B{cout<<'B';};//override B::go
>    void go(){cout<<"all";};//used for C,D and all
>
> };
>

I think we can use the following instead:

struct AA : A{
   virtual void go() {cout<<'B';}
};

struct BB : B{
   virtual void go() {cout<<'A';}
};

struct CD : C, D{
   virtual void go() {cout<<'all';}
};

struct all: AA,BB,CD{
};

I think it's enough for this usage.


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "frege" <gottlobfrege@gmail.com>
Date: Tue, 13 Mar 2007 11:48:40 CST
Raw View
On Mar 9, 6:24 pm, "jam" <farid.mehr...@gmail.com> wrote:
> consider:
>
> struct A{
>  virtual void go();
>
> };
>
> struct B{
>  virtual void go();
>
> };
>
> struct C{
>  virtual void go();
>
> };
>
> struct D{
>  virtual void go();
>
> };
>
> if a class inherits any two of the above then it will have to define
> its own version of go that will replace in both vtables inherited.
> Here is a humble syntax proposal:
>
> struct all: A,B,C,D{
>    // here is the syntax:
>    void go() A{cout<<'A';};//override A::go
>    void go() B{cout<<'B';};//override B::go
>    void go(){cout<<"all";};//used for C,D and all
>
> };
>

How about
struct all : A,B,C,D {
   void A::go() { cout << 'A' };
   void B::go() { cout << 'B' };
   void C::go() { cout << 'C' };
   void D::go() { all::C::go(); };
};

some of which MS Visual C++ already supports  (ie it supports adding
the base class to the declaration of a virtual member function - ie
'Base::func()'.  And it will complain if 'func' is not a member of
Base, which catches some coding errors.)

- Tony

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]