Topic: Add a way to tell the compiler to ignore ambiguities


Author: philippe_mori@hotmail.com ("Philippe Mori")
Date: Sun, 22 Dec 2002 07:13:15 +0000 (UTC)
Raw View
[...]
>
> In any case, the point was that there are already multiple and
> relatively simple and easy to use ways to achieve what the OP
> requested without changing C++.

I understand your point... Neverthless in generic code it is not always as
simple as with the sample above. If a want to uses a function on a wide
range of existing data type in existing code, any change may require
cascading changes throughout the code... or making a bunch of overload for
the generic code to take into account each possibility...

This is particullary annoying when in pratice not all compiler see the same
ambiguities (C++ Builder 4.0 and Visual C++ 6.0 have a lot of differences in
this area and are not standard in many cases). Having a way to tell prefered
function would help to limit extra code...

Says that we have a dozen of class that represent time (GPS, Gregorian,
system classes,...) and that some allows some conversions through
constructors and other through conversion operators, etc... Now I want to
define operators like +, -, += but I do not want to code each possibility by
hand (and I may not want to include extra depedencies between files since
some projects do not uses all of those classes), If I can tell the compiler
which functions to prefer, I may be able to write far less overload.

In pratice, I have found that I have some ambiguities when I tries to do
template like this:

template <typename T> T * Verify(T *p) { /* validate pointer */ return p; }

If I have a constant version "const T * Verify(const T *)", I have some
ambiguities and if not some code may not compile properly. This is common
under Visual C++ and C++ Builder... Anything that is a bit complex causes
some problems...

Another time where I find it a bit difficult to avoid all ambiguities under
both compiler was when I code a member function that would allows me to
convert C++ type to/from variant with far more conversion that _variant_t or
CCOMVariant does support. I resolve most ambiguities by adding extra
functions and classes. For exemple, my code was able to detect if a pointer
was derived from IUnknown and do the appropriate QueryInterface automaically
and it was possible to add user conversions...

It is not that it is impossible to do it with an extra keyword... I just
think that it could allows to limit the number of overload in some
situations... and I was wandering if other peoples think that such a
possibility would help them...

>
> Randy.
>


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_w@my-dejanews.com (Allan W)
Date: Mon, 23 Dec 2002 19:07:52 CST
Raw View
> allan_w@my-dejanews.com (Allan W) wrote
> > A more typical way to fix this problem (with today's language) is
> > one or both of:
> >   1. Change B's constructor that takes an A to be "explicit." You can
> >      still initialize a B with an A, but you can't implicitly convert.
> >      This one does EXACTLY what you wanted above -- when you call f()
> >      with an A, A's "operator B" is available but B's constructor is not.

rmaddox@isicns.com (Randy Maddox) wrote
> I like this one.  If access to the source is not an issue this would
> be my preferred solution too.

...and if the source is an issue, the OP's idea (adding a new keyword
"optional") won't help either.

> In any case, the point was that there are already multiple and
> relatively simple and easy to use ways to achieve what the OP
> requested without changing C++.

philippe_mori@hotmail.com ("Philippe Mori") wrote
> I understand your point... Neverthless in generic code it is not always as
> simple as with the sample above. If a want to uses a function on a wide
> range of existing data type in existing code, any change may require
> cascading changes throughout the code... or making a bunch of overload for
> the generic code to take into account each possibility...

Wouldn't you say the same thing for the "optional" keyword, for exactly
the same reason?

When would "optional" help, but "explicit" wouldn't?

> In pratice, I have found that I have some ambiguities when I tries to do
> template like this:
>
> template <typename T> T * Verify(T *p) { /* validate pointer */ return p; }
>
> If I have a constant version "const T * Verify(const T *)", I have some
> ambiguities and if not some code may not compile properly. This is common
> under Visual C++ and C++ Builder... Anything that is a bit complex causes
> some problems...

Verify(const T*) is supposed to be preferred, when the argument is const.
Verify(T*) is the only viable candidate, when the argument is not const.
This is not supposed to be ambiguous.

> Another time where I find it a bit difficult to avoid all ambiguities under
> both compiler was when I code a member function that would allows me to
> convert C++ type to/from variant with far more conversion that _variant_t or
> CCOMVariant does support.

Are you suggesting that you want conversions to type "variant" to be
transparent? Do you realize how much slower and fatter variants are than
any built-in type?

There are many good uses for a variant type, especially in COM development
or in mixed-language systems. Still, it's the antithesis of C++'s
"strong typing" concept and all that comes with it (run-time efficiency,
compile-time error detection, and so on). If you want to use variants,
don't be afraid to spell it's name in the source code -- so we all know
it wasn't an accident.

My $0.02, FWIW. IMHO. Etc.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: philippe_mori@hotmail.com ("Philippe Mori")
Date: Thu, 19 Dec 2002 15:40:53 +0000 (UTC)
Raw View
In some cases a call is ambiguous but it does not matters because both
function are equivalents. It would be usefull to tell that a function should
be ignored and/or preferred if an ambiguity occurs.

class A { optional operator B() { return B(); };
class B { B(const A &) {} };

void f(const B&);
A a;
f(a);

Normally the call f(a) would result in an ambiguity but since conversion
operator is marked as optional, we would prefer the conversion with the
constructor.


---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rmaddox@isicns.com (Randy Maddox)
Date: Thu, 19 Dec 2002 19:42:43 +0000 (UTC)
Raw View
philippe_mori@hotmail.com ("Philippe Mori") wrote in message news:<ZmkM9.5827$cN3.972258@news20.bellglobal.com>...
> In some cases a call is ambiguous but it does not matters because both
> function are equivalents. It would be usefull to tell that a function should
> be ignored and/or preferred if an ambiguity occurs.
>
> class A { optional operator B() { return B(); };
> class B { B(const A &) {} };
>
> void f(const B&);
> A a;
> f(a);
>
> Normally the call f(a) would result in an ambiguity but since conversion
> operator is marked as optional, we would prefer the conversion with the
> constructor.
>
>

Can this not already be accomplished by one of:

  f(a.operator B());

  f(B(a));

And does this not leave the decision in the hands of the caller, which
is probably where it ought to be?

Randy.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: allan_w@my-dejanews.com (Allan W)
Date: Fri, 20 Dec 2002 03:36:16 +0000 (UTC)
Raw View
rmaddox@isicns.com (Randy Maddox) wrote
> philippe_mori@hotmail.com ("Philippe Mori") wrote
> > In some cases a call is ambiguous but it does not matters because both
> > function are equivalents. It would be usefull to tell that a function should
> > be ignored and/or preferred if an ambiguity occurs.
> >
> > class A { optional operator B() { return B(); };
> > class B { B(const A &) {} };
> >
> > void f(const B&);
> > A a;
> > f(a);
> >
> > Normally the call f(a) would result in an ambiguity but since conversion
> > operator is marked as optional, we would prefer the conversion with the
> > constructor.
> >
> >
>
> Can this not already be accomplished by one of:
>
>   f(a.operator B());
>
>   f(B(a));
>
> And does this not leave the decision in the hands of the caller, which
> is probably where it ought to be?

If I had a library with two classes designed as above (without the
"optional" of course), I'd call it buggy.

I would call both of your code snippets "workarounds." I would complain
about the library bitterly at every excuse. I'd actually make something
of an ass of myself, and regret doing so. (Maybe I'm being too honest
here? I once had to work with a buggy third-party library -- it didn't
have that problem, but it had dozens of others, and I had to get my
program working fast! My boss kept blaming me, and I kept pointing at
the library bugs, and pretty soon we were both very obnoxious... not
something I'm proud of... but enough digression.)

A more typical way to fix this problem (with today's language) is
one or both of:
  1. Change B's constructor that takes an A to be "explicit." You can
     still initialize a B with an A, but you can't implicitly convert.
     This one does EXACTLY what you wanted above -- when you call f()
     with an A, A's "operator B" is available but B's constructor is not.

  2. Change A's "operator B" to something else, such as "as_B()".
     This works with anyone that can read documentation (which is
     a minority, I grant... also, templates can't read documentation,
     so they don't know how to call as_B()).

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rmaddox@isicns.com (Randy Maddox)
Date: Fri, 20 Dec 2002 16:36:47 +0000 (UTC)
Raw View
allan_w@my-dejanews.com (Allan W) wrote in message news:<7f2735a5.0212191709.64b98513@posting.google.com>...
>
> A more typical way to fix this problem (with today's language) is
> one or both of:
>   1. Change B's constructor that takes an A to be "explicit." You can
>      still initialize a B with an A, but you can't implicitly convert.
>      This one does EXACTLY what you wanted above -- when you call f()
>      with an A, A's "operator B" is available but B's constructor is not.
>

I like this one.  If access to the source is not an issue this would
be my preferred solution too.

In any case, the point was that there are already multiple and
relatively simple and easy to use ways to achieve what the OP
requested without changing C++.

Randy.

---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]