Topic: Overloading by return type?!
Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Mon, 30 Jul 2001 10:38:37 GMT Raw View
Consider examples like this one:
double x = 1 + foo();
What type should the compiler use as the expected return
type when resolving overloading on the return type for foo()?
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
The University of Melbourne | of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 30 Jul 2001 16:25:24 GMT Raw View
In article <9k3db6$an8$1@mulga.cs.mu.OZ.AU>, fjh@cs.mu.OZ.AU (Fergus
Henderson) wrote:
>Consider examples like this one:
>
> double x = 1 + foo();
>
>What type should the compiler use as the expected return
>type when resolving overloading on the return type for foo()?
It does not seem difficult to find an implementation in order to handle
that: Just write a Prolog program with the different type combination
possibilities as constraints.
Then in a case like the one above, one will probably find that the
resolution is ambiguous. So then is the question, should the programmer be
left out in the cold, or should one have some kind of type ambiguity
resolution mechanism? And there is also the question on how easy it is for
a programmer to use such a complex type system.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: markw65@my-deja.com (Mark Williams)
Date: Mon, 30 Jul 2001 20:19:42 GMT Raw View
fjh@cs.mu.OZ.AU (Fergus Henderson) wrote in message news:<9k3db6$an8$1@mulga.cs.mu.OZ.AU>...
> Consider examples like this one:
>
> double x = 1 + foo();
>
> What type should the compiler use as the expected return
> type when resolving overloading on the return type for foo()?
Why not try it? The same problem already exists in the current
standard, so the rules already exist:
class foo {
// uncomment whichever flavours you want to
// allow.
// operator int();
// operator float();
// operator double();
};
int main()
{
double x = 1 + foo();
}
Depending on which conversion operators you supply (which is exactly
analogous to providing functions named foo with different return
types), you will get a successful compilation, an error due to no
suitable conversion, or an ambiguous conversion. This is exactly what
should happen for functions overloaded by return type...
Mark Williams
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: ejr@cs.berkeley.edu (Edward Jason Riedy)
Date: Wed, 1 Aug 2001 23:08:19 GMT Raw View
And Fergus Henderson writes:
- Consider examples like this one:
-
- double x = 1 + foo();
-
- What type should the compiler use as the expected return
- type when resolving overloading on the return type for foo()?
On x86-like platforms, long double. On platforms that don't
support more than double in hardware, double. Unless foo()
only returns long double or quad, in which case the expression
should be evaluated in long double or quad, respectively.
Arithmetic expressions, especially in floating point, benefit
greatly from having an _expression type_, a common type for the
whole expression. The expression type should be determined by
a scan for widest-need, with lower bounds on the types determined
by hardware support.
This lets examples like
double x = sin(y)*sin(y) + cos(y)*cos(y);
match user's expectations more often. If computed in a double-
extended precision (including quad), this will be 1.0 for all
double data. (Well, assuming elementary functions with errors
that are easy to achieve quickly.) If computed only in double
from double data, you're likely to be off by a few units in
the last place.
Admittedly it's not always possible. Imagine your foo()
returning a time-date type... A type-class like mechanism could
clear this up. I don't suppose there's any chance that type
classes could be introduced into C++?
Oh, you're asking what type would the compiler use rather than
should? ;)
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://www.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Thu, 2 Aug 2001 11:35:01 GMT Raw View
In article <9ka1t7$mng$1@agate.berkeley.edu>, ejr@cs.berkeley.edu (Edward
Jason Riedy) wrote:
>And Fergus Henderson writes:
> - Consider examples like this one:
> -
> - double x = 1 + foo();
> -
> - What type should the compiler use as the expected return
> - type when resolving overloading on the return type for foo()?
>
>On x86-like platforms, long double. On platforms that don't
>support more than double in hardware, double. Unless foo()
>only returns long double or quad, in which case the expression
>should be evaluated in long double or quad, respectively.
I did not think about that, but this is an interesting aspect: Many
platforms have a type which is the most efficient. For example, if using
say a float that may be slower than a double because the double is
hardware supported and the float is first converted to a double before the
computations.
So one might exploit this in order to resolve the problem that C++
inherits from C in the form of circular type conversions that may cause
ambiguities: Each compiler has a preferred type to choose in such
circumstances.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Mon, 18 Jun 2001 18:14:39 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:7fjW6.1167$35.1060773@typhoon.san.rr.com...
[snip]
> Lets even assume it is the same mechanism, than in the case of the function
> pointer
> you have more help, because you have something you can chek the type with
> and
> therefore match those types and if they don't match it is a compile time
> error.
> In the case of the sizeof operator there is nothing to compare it against,
> and you would
> have been forced to resolve explicitly which function do you mean, which I
> personally
> don't think would be a nice thing to do.
> e.g.
I'm not talking about *using* the sizeof operator. I'm saying that the sizeof
mechanism determines the type of an expression, which could be easily reused to
resolve on return type.
> double f();
> float f();
>
> double(*pd)() = f; // would find correct match
> size_t sz = sizeof f();
> // what should it be?
>
> to make it work something similar to the following
> size_t sz = static_cast<double>(f());
>
>
> I know there are contra examples, but yet I believe it shows that it would
> make something,
> which is at the current moment more elegant and less error prone, less
> elegant and more
> confusing.
You are completely misunderstanding what my references to the sizeof operator
are about. I am not asserting that the sizeof operator itself should be used,
only its type determination mechanism, nor am I saying that the size of an
object has anything to do with overloading on return type. Many people already
want a "typeof" operator, and one of the primary arguments for that is that the
mechanism is already implemented inside of "sizeof," so it would be easy to
implement. I will try to be as clear as I can be:
1. The sizeof operator determines the type of an expression, then it evaluates
the size of that type.
2. We only care about the first part here: "obtaining the type of an
expression."
3. One of the primary reasons for disallowing overloading on return type is to
avoid context dependence, meaning "anything other than parameters," so that the
function can be resolved "bottom-up" (in other words, with just the parameters).
4. The type determination part of the sizeof implementation can be used to
determine the "context" of a function call and is already implemented.
5. Context is already used in taking the address of a function. Since there
are no parameter types specified, the function cannot be resolved in a bottom-up
fashion.
Therefore:
1. A compiler already must be able to deduce the context.
2. A compiler cannot use bottom-up resolution exclusively.
Which removes one of the primary objections to overloading via return type.
Other possible issues:
Legacy Code:
If the return type was given equal weight with parameters in overload
resolution, it would break tons of existing code. However, if return type
resolution was only invoked when parameter resolution failed, absolutely *zero*
legacy code would be broken, since it would never have compiled in the first
place with the ambiguous call of an overloaded function.
Complexity:
>From a user's point of view, the return type is not really any different than a
parameter, and often parameters are used for return values. The added
complexity would be extremely minor. The various syntactic constructs that can
occur outside of a function call can also occur in the parameters of a function
call. Therefore, the type conversion rules, etc., could be exactly the same as
for parameters. Sometimes you would have to explicitly resolve the function via
static casts just like you sometimes must for parameters. Consider:
int f();
double f();
int g(int);
int g(double);
int main() {
int x = 1.0 + f();
x = g(1.0 + x);
return 0;
}
Via normal type conversion rules,
int x = 1.0 + f();
would have to invoke double f() because 1.0 is a double.
Likewise,
x = g(1.0 + x);
would have to invoke int g(double) because (1.0 + x) is a double.
Both are cases that would use the exact same conversion rules, the only major
difference is that one does type coercion and one does function.
To be clearer, the compiler must deduce that x, which is an int, must be
coerced to a double in order to do floating-point computation in 1.0 + x.
Likewise, the compiler could, just as easily, prefer the function that returns a
double in order to do floating-point computation in 1.0 + f().
In several obvious cases, you would have to be explicit. But, once again, that
is no different than parameters:
void f(int);
void f(short);
int main() {
signed char x = 0;
f(x); // ambiguous
f(static_cast<short>(x)); // explicit resolution
return 0;
}
- vs. -
int f();
short f();
int main() {
signed char x = 0;
x = f(); // ambiguous
x = static_cast<short>(f)(); // explicit resolution
return 0;
}
The only *real* difference is where "static_cast<short>(..)" is.
I prefer "static_cast<short>(f)()" rather than "static_cast<short>(f())" because
I think it matches (*pf)() better, it decreases the number of nested
parenthesis, and distinguishes it from a "regular" static cast.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Mon, 18 Jun 2001 18:16:05 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:qucW6.171947$p33.3571677@news1.sttls1.wa.home.com...
>
> "Samuel Schulman" <s.schulman@berlin.de> wrote in message
> news:vgXV6.978$35.490637@typhoon.san.rr.com...
> [snip]
> > > > I am really having a hard time to understand the coherence between
the
> > > > sizeof operator
> > > > and the 'overloading by return value', and how the mechanism to
support
> > > > overloading, based on return type, does already exists?
> > >
> > > sizeof must evaluate the "type" of an expression in order to discover
its
> > size.
> >
> > You should read in the ISO14882, 5.3.3 about the operator sizeof,
> > and you will find out that the expression is not evaluated.
> > [whereas in ISO9899 C there is an exception]
>
> This has nothing to do with the expression being evaluated. It has to do
with
> sizeof determining the type of the result of the expression in order to
> determine its size. This has absolutely nothing to do with calling
functions or
> adding/substracting/etc. anything, nor did I imply that it did.
I, as I already posted, understood you wrong.
> > > For example,
> > > if I have a function that returns a struct with two ints:
> > >
> > > ----------
> > >
> > > struct A {
> > > int x, y;
> > > A(int p, int q) : x(p), y(q) { return; }
> > > };
> > >
> > > A get() {
> > > return A(0, 0);
> > > }
> > >
> > > ----------
> > >
> > > and then I pseudo-call that function:
> > >
> > > ----------
> > >
> > > void f() {
> > > std::size_t s = sizeof(get());
> > > }
> > >
> > > ----------
> > >
> > > sizeof must determine that the type of "get()" is "A" and return the
size
> > of A.
> > > Therefore, in this example: sizeof(A) == sizeof(get())
> >
> > The type of "get()" is not A.
> > You might can call A, as sometimes reffered to, the value of the
function,
> > but not the type.
>
> The type of the *expression* "get()" is A. This does not imply that get()
is
> called, which it isn't, and that is exactly why I said "psuedo-call." The
type
> of the function get() is not A, that is true. However, the type of the
> expression "get()" is, indeed, A. Similarly the type of two ints added
together
> is "int":
Now we are in sync regarding this point.:)
> int x, y;
> sizeof(x + y);
>
> If A had a "A operator+(const A&)", then this the type of this expression
would
> also be A:
>
> get() + get()
>
> As a matter of fact, get() doesn't even need to be implemented just
declarated
> and the above example would compile (if you changed f() to int main() :)).
I am not going to argue here:)
> > > the backend of sizeof (i.e. type determination) is all that is
necessary
> > in
> > > order to determine the "context" of a function call that is overloaded
via
> > > return type.
> > >
> > > Furthermore, this same type of mechanism is used with function
pointers.
> > In
> > > order to select the correct overload of a function, it uses the type
of
> > function
> > > pointer that is being assigned to.
> >
> > As sizeof works different than you explained, it cannot be the same.
>
> sizeof works exactly as I have explained, it absolutely *must* by
definition in
> the standard evaluate the type of an expression to determine the size of
the
> result of that expression. I'm just using sizeof to point out that the
supposed
> "context" problems with overloading via return type are already mandated
and
> handled by the current definition of C++ in other, similar areas.
Maybe you are right, and sizeof uses the same mechanism, yet the compiler
has more help when he resolves function-pointer assignment.
> > > ----------
> > >
> > > void f();
> > > void g(double);
> > > int f(double);
> > >
> > > typedef void (*fp1)();
> > > typedef int (*fp2)(double);
> > >
> > > void h() {
> > > fp1 x = &f;
> > > fp2 y = &f;
> > > fp1 z = &g; // error: type mismatch
> > > }
> > >
> > > ----------
>
> By the way, z should be an fp2 where the function differs only be return
type.
> My mistake.
>
> > >
> > > In other words, it must already look at x and y to find the address of
the
> > > correct f(). In the case of z, however, it must know the type of z
and
> > the,
> > > specifically, the type of the return value of g() in order to raise a
type
> > > mismatch error.
> >
> > This example is much simpler to resolve than a function call, and will
not
> > lead to unexpected behaviour,
> > as there is no implicit conversion and the compiler will tell you, if
the
> > complete types don't match.
>
> This is a compile-time selection of several functions with the same name.
Overl
> oad resolution is exactly the same thing--a compile-time selection of
several
> functions with the same name. There is no run-time behavior here at all.
> Overload resolution merely picks the function (at compile-time) and that
*exact*
> function is always called at run time (barring catastrophic failure). My
point
> with function pointers is that they use a *contextual* form of overload
> resolution. Type-conversion has nothing to do with it. I'm merely
pointing out
> that compilers must already determine which function based on context. In
the
> case of function pointers and references, based entirely on context.
Well here I don't agree, you say barring catastrophic failure, catastrophic
depending what is supposed to happen and what actually happens. Yes at
runtime, you will have always the same funcion called, this is without a
doubt true, but which one the compiler will decide to call might be
unexpected,
if the return type is taken into consideration.
> Assignment/initialization of function pointers and initialization of
function
> references *is* a compile-time overload resolution. How are these two
much
> different?
>
> void g(double);
> void g(int);
>
> typedef void (&rg_dbl)(double);
>
> rg_dbl g_ref = g; // compile-time overload resolution based on context
>
> int main() {
> g_ref(0.0);
> g(0.0); // compile-time overload resolution based on parameter
> return 0;
> }
>
> > If you have to resolve a function you don't have this guarantee as their
is
> > something like type-promotion and implicit type-conversion of arguments,
> > which helps out to resolve those issues.
> > And as I believe the current conversion rules are complex enough,
> > and should not be made even more complex for a feature,
> > we all most likely are better off without, seen in a broader
perspective.
>
> Or a lack of a broader perspective as the case may be. I'll give you an
even
> better example:
I guess here everybody has its own perspective:)
> namespace A {
> double f() {
> std::cout << "double" << std::endl;
> return 0.0;
> }
> }
>
> namespace B {
> int f() {
> std::cout << "int" << std::endl;
> return 0;
> }
> }
>
> namespace C {
> using namespace A; // necessary to get both f's into the same scope
> using namespace B;
> typedef double (*dbl_pf)();
> typedef int (*int_pf)();
> }
>
> int main() {
> C::dbl_pf x = &C::f;
> C::int_pf y = &C::f;
> (*x)();
> (*y)();
> return B::f();
> }
>
> This is an example of overload resolution with function pointers based
entirely
> on return type, which produces the output:
>
> double
> int
> int
I cannot see an overload resolution based entirely on return type,
'faking it' as you refer in the next paragraph is more appropriate.
> As it should. Whereas calling C::f directly would be ambiguous. The fact
that
> it is possible to "fake" overload by return type like this is another
argument
> that it should be generalized. In order to make C++ simpler and more
general,
> you have two options:
>
> 1. change the address-of-function syntax to include parameter types,
which
> would break millions of lines of code.
>
> 2. generalize context dependent overloading via return type, which is
> considered only if parameter resolution is ambigious, which would break
exactly
> *zero* code.
>
> In order to make C++ more general, *easier* to learn, more orthogonal,
etc., the
> only feasible option is #2, which would not be anymore complicated than
> parameter resolution already is. There are times that you would have to
be
> explicit, just like with parameters, and there are many times that you
would
> not. Consider:
I think it will make it more complicated.
> double f();
> int f();
>
> int g(double);
> int g(int);
>
> int main() {
> double x = 1.0 + f();
> x = 1.0 + static_cast<int>(f)();
> int y = 0;
> y = g(1.0 + g(static_cast<double>(y)));
> return 0;
> }
>
> It seems to me that the only real difference is where the paranthesis and
static
> casts are, other than "bottom-up" resolution vs. context resolution (both
of
> which are already implemented in different mechanisms: function call vs.
> function address).
I am sorry, and please don't take this personal, I really would not want to
see things like this introduced into C++.
> The biggest reason of all:
>
> double f(double, double);
> int f(int, int); // you can have this
>
> double f(double);
> int f(int); // you can have this as well
>
> double f();
> int f(); // but you can't have this, despite an obvious and reasonable
> progression
>
> > > Therefore, if I has something slightly more convoluted:
>
> [snip old example]
>
> > The only difference to the preceding example, I can see, is that it is
more
> > intricately implemented, semantically seen though it appears to me as
being
> > the same.
>
> It is the same thing, just slightly more complicated "context." Maybe I
should
> have made it more complicated:
>
> typedef int (*fp1)(int);
> typedef double (*fp2)(double);
>
> int a_default_func(int arg);
> double a_default_func(double arg);
>
> fp1 _1a = &a_default_func, _1b = &a_default_func;
> fp2 _2a = &a_default_func, _2b = &a_default_func;
>
> inline fp1& select(int a) {
> if (a) return _1a;
> return _1b;
> }
>
> inline fp2& select(double a) {
> if (a > 0.0) return _2a;
> return _2b;
> }
>
> int a_func(int arg) { return arg; }
> double a_func(double arg) { return arg; }
>
> int main() {
> double x = 0.0;
> int y = 0;
> // manipulate x and y for a while...
> select(x) = &a_func;
> select(y) = &a_func;
> return (*_1a)(0);
> }
>
> This is just an example of contextual resolution, that's all. In this
example
> the type of the "expression" select(...) is slightly less obvious, which
just
> increases the context dependence somewhat, further pointing out the fact
that
> context is already used for resolution.
>
> Paul Mensonides
>
> ---
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 19 Jun 2001 12:16:48 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:lWhX6.4184$35.2696152@typhoon.san.rr.com...
> I guess here everybody has its own perspective:)
>
> > namespace A {
> > double f() {
> > std::cout << "double" << std::endl;
> > return 0.0;
> > }
> > }
> >
> > namespace B {
> > int f() {
> > std::cout << "int" << std::endl;
> > return 0;
> > }
> > }
> >
> > namespace C {
> > using namespace A; // necessary to get both f's into the same scope
> > using namespace B;
> > typedef double (*dbl_pf)();
> > typedef int (*int_pf)();
> > }
> >
> > int main() {
> > C::dbl_pf x = &C::f;
> > C::int_pf y = &C::f;
> > (*x)();
> > (*y)();
> > return B::f();
> > }
> >
> > This is an example of overload resolution with function pointers based
> entirely
> > on return type, which produces the output:
> >
> > double
> > int
> > int
>
> I cannot see an overload resolution based entirely on return type,
> 'faking it' as you refer in the next paragraph is more appropriate.
Overload resolution == selecting one of several functions with the same name at
compile-time.
int main() {
C::dbl_pf x = &C::f; // overload resolution
C::int_pf y = &C::f; // overload resolution
...
}
Whether or not this is overload resolution based on parameters is irrelevant.
However, this is overload resolution. The compiler *is* selecting from a group
of functions with the same name. That *is* overload resolution. What if I do
something similar only with parameters:
//-- begin example --//
#include /* stuff from above except main */
typedef double (& dbl_rf)();
typedef int (& int_rf)();
void func(long x, dlb_rf y) {
y();
return;
}
void func(int x, int_rf y) {
y();
return;
}
int main() {
func(0, C::f);
func(0L, C::f);
return;
}
//-- end example --//
Or better yet...
//-- begin example --//
#include <ostream>
/* Base template so I get names like Functor<0> which I like better than
Functor_0 or Functor0, etc,
but you can only instantiate the specific defined ones.
I use functors only so I get the syntax that I want:
ambiguity_cast<...>(functionName)(params) */
template<int C> struct Functor;
template<> struct Functor<0> {
template<class R> class Impl {
private:
R (* m_pf)(void);
public:
Impl(R (*pf)(void)) : m_pf(pf) {
return;
}
R operator()(void) {
return (*m_pf)();
}
};
};
template<> struct Functor<1> {
template<class R, class P1> class Impl {
private:
R (* m_pf)(P1);
public:
Impl(R (*pf)(P1)) : m_pf(pf) {
return;
}
R operator()(P1 a) {
return (*m_pf)(a);
}
};
};
template<> struct Functor<2> {
template<class R, class P1, class P2> class Impl {
private:
R (* m_pf)(P1, P2);
public:
Impl(R (*pf)(P1, P2)) : m_pf(pf) {
return;
}
R operator()(P1 a, P2 b) {
return (*m_pf)(a);
}
};
};
// repeat for more parameters
/* These are function resolution helpers, they allow you to resolve ambiguous
functions on return/paramter types. */
template<class R> inline Functor<0>::Impl<R> ambiguity_cast(R (& rf)(void)) {
return Functor<0>::Impl<R>(rf);
}
template<class R, class P1> inline Functor<1>::Impl<R, P1> ambiguity_cast(R (&
rf)(P1)) {
return Functor<1>::Impl<R, P1>(rf);
}
template<class R, class P1, class P2> inline Functor<2>::Impl<R, P1, P2>
ambiguity_cast(R (& rf)(P1, P2)) {
return Functor<2>::Impl<R, P1, P2>(rf);
}
// repeat for more parameters
namespace A {
double f() {
std::cout << "double" << std::endl;
return 0.0;
}
double f(int) {
std::cout << "double // int" << std::endl;
return 0.0;
}
double f(int, int) {
std::cout << "double // int, int" << std::endl;
return 0.0;
}
}
namespace B {
int f() {
std::cout << "int" << std::endl;
return 0;
}
int f(int) {
std::cout << "int // int" << std::endl;
return 0;
}
int f(int, int) {
std::cout << "int // int, int" << std::endl;
return 0;
}
}
namespace C {
using A::f;
using B::f;
}
int main() {
int x = ambiguity_cast<int>(C::f)();
x = ambiguity_cast<int, int>(C::f)(10);
double y = ambiguity_cast<double>(C::f)();
return 0;
}
//-- end example --//
Here, I have...
double f();
double f(int);
double f(int, int);
int f();
int f(int);
int f(int, int);
....all in the same scope. Notice any call to any of these functions would be
ambiguous, with no *normal* way to explicitly resolve them.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: James Dennett <jdennett@acm.org>
Date: Thu, 14 Jun 2001 22:50:17 GMT Raw View
Samuel Schulman wrote:
>
> "Paul Mensonides" <pmenso57@home.com> wrote in message
> news:wpvV6.157904$p33.3303638@news1.sttls1.wa.home.com...
> >
> > "Samuel Schulman" <s.schulman@berlin.de> wrote in message
> > news:TrOU6.2282$35.1905982@typhoon.san.rr.com...
> >
> > [snip]
> >
> > > I am really having a hard time to understand the coherence between the
> > > sizeof operator
> > > and the 'overloading by return value', and how the mechanism to support
> > > overloading, based on return type, does already exists?
> >
> > sizeof must evaluate the "type" of an expression in order to discover its
> size.
>
> You should read in the ISO14882, 5.3.3 about the operator sizeof,
> and you will find out that the expression is not evaluated.
> [whereas in ISO9899 C there is an exception]
The expression is not evaluated, but the *type* of the expression
is evaluated (at compile time). Paul was quite correct. sizeof
must evaluate the (static) type of an expression in order to
discover its size. Paul did not claim that the expression itself
was evaluated -- there's no need to evaluate an expression in
order to determine (aka "evaluate") its static type.
> > For example,
> > if I have a function that returns a struct with two ints:
> >
> > ----------
> >
> > struct A {
> > int x, y;
> > A(int p, int q) : x(p), y(q) { return; }
> > };
> >
> > A get() {
> > return A(0, 0);
> > }
> >
> > ----------
> >
> > and then I pseudo-call that function:
> >
> > ----------
> >
> > void f() {
> > std::size_t s = sizeof(get());
> > }
> >
> > ----------
> >
> > sizeof must determine that the type of "get()" is "A" and return the size
> of A.
> > Therefore, in this example: sizeof(A) == sizeof(get())
>
> The type of "get()" is not A.
It seems to me that it is A. What else could it be? "get()" is
an expression (a function call) and it evaluates to an object of
type A.
> You might can call A, as sometimes reffered to, the value of the function,
> but not the type.
The "value of the function" cannot be A, as A is a type, not
an object. Functions return values only at runtime; and
sizeof works at compile-time (in C++ at least).
> > the backend of sizeof (i.e. type determination) is all that is necessary
> in
> > order to determine the "context" of a function call that is overloaded via
> > return type.
> >
> > Furthermore, this same type of mechanism is used with function pointers.
> In
> > order to select the correct overload of a function, it uses the type of
> function
> > pointer that is being assigned to.
>
> As sizeof works different than you explained, it cannot be the same.
I believe that Paul's explanation was correct. Why do you believe
otherwise?
-- James Dennett
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Fri, 15 Jun 2001 04:49:51 GMT Raw View
"James Dennett" <jdennett@acm.org> wrote in message
news:3B292C21.68867FD1@acm.org...
> The expression is not evaluated, but the *type* of the expression
> is evaluated (at compile time). Paul was quite correct. sizeof
> must evaluate the (static) type of an expression in order to
> discover its size. Paul did not claim that the expression itself
> was evaluated -- there's no need to evaluate an expression in
> order to determine (aka "evaluate") its static type.
Speaking of sizeof, is this legal:
struct X {
int v;
virtual X* get() {
return this;
}
};
struct Y : public X {
int v2;
Y* get() { // overrides with covariance
return this;
}
};
int main() {
Y y;
X* x = &y;
sizeof(*(x->get()));
return 0;
}
I'm just curious what the result of this is supposed to be given a covariant
return type of a virtual function, if it legal at all. Does anybody know?
What about this...
int main() {
Y y;
Y* pY = &y;
sizeof(*(pY->X::get()));
sizeof(*(pY->Y::get()));
return 0;
}
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Fri, 15 Jun 2001 09:47:25 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:4edW6.172109$p33.3578423@news1.sttls1.wa.home.com...
> "James Dennett" <jdennett@acm.org> wrote in message
> news:3B292C21.68867FD1@acm.org...
>
> > The expression is not evaluated, but the *type* of the expression
> > is evaluated (at compile time). Paul was quite correct. sizeof
> > must evaluate the (static) type of an expression in order to
> > discover its size. Paul did not claim that the expression itself
> > was evaluated -- there's no need to evaluate an expression in
> > order to determine (aka "evaluate") its static type.
>
> Speaking of sizeof, is this legal:
>
> struct X {
> int v;
> virtual X* get() {
> return this;
> }
> };
>
> struct Y : public X {
> int v2;
> Y* get() { // overrides with covariance
> return this;
> }
> };
>
> int main() {
> Y y;
> X* x = &y;
> sizeof(*(x->get()));
> return 0;
> }
>
> I'm just curious what the result of this is supposed to be given a
covariant
> return type of a virtual function, if it legal at all. Does anybody know?
This was simple.
This statement sizeof(*(x->get())) uses the static type of the pointer,
therefore the size will be that of X.
> What about this...
>
> int main() {
> Y y;
> Y* pY = &y;
> sizeof(*(pY->X::get())); // #1
> sizeof(*(pY->Y::get())); // #2
> return 0;
> }
>
> Paul Mensonides
>
This was more tricky, I had to back up my assumption first.
And here as well, the complete static type is taken. And as both
postfix-expressions are explicitly referring to the function, the sizeof
will be that of X in case #1, and the sizeof Y in case #2.
- Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Fri, 15 Jun 2001 09:48:36 GMT Raw View
"James Dennett" <jdennett@acm.org> wrote in message
news:3B292C21.68867FD1@acm.org...
> Samuel Schulman wrote:
> >
> > "Paul Mensonides" <pmenso57@home.com> wrote in message
> > news:wpvV6.157904$p33.3303638@news1.sttls1.wa.home.com...
> > >
> > > "Samuel Schulman" <s.schulman@berlin.de> wrote in message
> > > news:TrOU6.2282$35.1905982@typhoon.san.rr.com...
> > >
> > > [snip]
> > >
> > > > I am really having a hard time to understand the coherence between
the
> > > > sizeof operator
> > > > and the 'overloading by return value', and how the mechanism to
support
> > > > overloading, based on return type, does already exists?
> > >
> > > sizeof must evaluate the "type" of an expression in order to discover
its
> > size.
> >
> > You should read in the ISO14882, 5.3.3 about the operator sizeof,
> > and you will find out that the expression is not evaluated.
> > [whereas in ISO9899 C there is an exception]
>
> The expression is not evaluated, but the *type* of the expression
> is evaluated (at compile time). Paul was quite correct. sizeof
> must evaluate the (static) type of an expression in order to
> discover its size. Paul did not claim that the expression itself
> was evaluated -- there's no need to evaluate an expression in
> order to determine (aka "evaluate") its static type.
I must have misunderstood what he ment.
> > > For example,
> > > if I have a function that returns a struct with two ints:
> > >
> > > ----------
> > >
> > > struct A {
> > > int x, y;
> > > A(int p, int q) : x(p), y(q) { return; }
> > > };
> > >
> > > A get() {
> > > return A(0, 0);
> > > }
> > >
> > > ----------
> > >
> > > and then I pseudo-call that function:
> > >
> > > ----------
> > >
> > > void f() {
> > > std::size_t s = sizeof(get());
> > > }
> > >
> > > ----------
> > >
> > > sizeof must determine that the type of "get()" is "A" and return the
size
> > of A.
> > > Therefore, in this example: sizeof(A) == sizeof(get())
> >
> > The type of "get()" is not A.
>
> It seems to me that it is A. What else could it be? "get()" is
> an expression (a function call) and it evaluates to an object of
> type A.
I am not sure, if you mean the type of the function 'get()' is A, than I can
pretty sure say, that you cannot call the return type of a function as the
type of the
function itself, although it is part of the complete function type(ISO14882
8.3.5.4).
Therefore the type of the function is 'A(*)(void)'.
And if overloading by return type were allowed, the sizeof operator would
not be able
anymore easily to evaluate the expression during compilation.
> > You might can call A, as sometimes reffered to, the value of the
function,
> > but not the type.
>
> The "value of the function" cannot be A, as A is a type, not
> an object. Functions return values only at runtime; and
> sizeof works at compile-time (in C++ at least).
It seems to me that you misunderstood what I ment.
A type int, is type int, no matter how you look at it, in respect to
compile-time or runtime.
So to say it again, "value of a function" is only one synomym used sometimes
for a function, based on its 'return type'.
(I remember seeing this term used in some literature, one of them if I
recall correctly, was The C programming language)
> > > the backend of sizeof (i.e. type determination) is all that is
necessary
> > in
> > > order to determine the "context" of a function call that is overloaded
via
> > > return type.
> > >
> > > Furthermore, this same type of mechanism is used with function
pointers.
> > In
> > > order to select the correct overload of a function, it uses the type
of
> > function
> > > pointer that is being assigned to.
> >
> > As sizeof works different than you explained, it cannot be the same.
>
> I believe that Paul's explanation was correct. Why do you believe
> otherwise?
Lets even assume it is the same mechanism, than in the case of the function
pointer
you have more help, because you have something you can chek the type with
and
therefore match those types and if they don't match it is a compile time
error.
In the case of the sizeof operator there is nothing to compare it against,
and you would
have been forced to resolve explicitly which function do you mean, which I
personally
don't think would be a nice thing to do.
e.g.
double f();
float f();
double(*pd)() = f; // would find correct match
size_t sz = sizeof f();
// what should it be?
to make it work something similar to the following
size_t sz = static_cast<double>(f());
I know there are contra examples, but yet I believe it shows that it would
make something,
which is at the current moment more elegant and less error prone, less
elegant and more
confusing.
> -- James Dennett
>
- Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Fri, 15 Jun 2001 16:09:46 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:vgXV6.978$35.490637@typhoon.san.rr.com...
[snip]
> > > I am really having a hard time to understand the coherence between the
> > > sizeof operator
> > > and the 'overloading by return value', and how the mechanism to support
> > > overloading, based on return type, does already exists?
> >
> > sizeof must evaluate the "type" of an expression in order to discover its
> size.
>
> You should read in the ISO14882, 5.3.3 about the operator sizeof,
> and you will find out that the expression is not evaluated.
> [whereas in ISO9899 C there is an exception]
This has nothing to do with the expression being evaluated. It has to do with
sizeof determining the type of the result of the expression in order to
determine its size. This has absolutely nothing to do with calling functions or
adding/substracting/etc. anything, nor did I imply that it did.
> > For example,
> > if I have a function that returns a struct with two ints:
> >
> > ----------
> >
> > struct A {
> > int x, y;
> > A(int p, int q) : x(p), y(q) { return; }
> > };
> >
> > A get() {
> > return A(0, 0);
> > }
> >
> > ----------
> >
> > and then I pseudo-call that function:
> >
> > ----------
> >
> > void f() {
> > std::size_t s = sizeof(get());
> > }
> >
> > ----------
> >
> > sizeof must determine that the type of "get()" is "A" and return the size
> of A.
> > Therefore, in this example: sizeof(A) == sizeof(get())
>
> The type of "get()" is not A.
> You might can call A, as sometimes reffered to, the value of the function,
> but not the type.
The type of the *expression* "get()" is A. This does not imply that get() is
called, which it isn't, and that is exactly why I said "psuedo-call." The type
of the function get() is not A, that is true. However, the type of the
expression "get()" is, indeed, A. Similarly the type of two ints added together
is "int":
int x, y;
sizeof(x + y);
If A had a "A operator+(const A&)", then this the type of this expression would
also be A:
get() + get()
As a matter of fact, get() doesn't even need to be implemented just declarated
and the above example would compile (if you changed f() to int main() :)).
> > the backend of sizeof (i.e. type determination) is all that is necessary
> in
> > order to determine the "context" of a function call that is overloaded via
> > return type.
> >
> > Furthermore, this same type of mechanism is used with function pointers.
> In
> > order to select the correct overload of a function, it uses the type of
> function
> > pointer that is being assigned to.
>
> As sizeof works different than you explained, it cannot be the same.
sizeof works exactly as I have explained, it absolutely *must* by definition in
the standard evaluate the type of an expression to determine the size of the
result of that expression. I'm just using sizeof to point out that the supposed
"context" problems with overloading via return type are already mandated and
handled by the current definition of C++ in other, similar areas.
> > ----------
> >
> > void f();
> > void g(double);
> > int f(double);
> >
> > typedef void (*fp1)();
> > typedef int (*fp2)(double);
> >
> > void h() {
> > fp1 x = &f;
> > fp2 y = &f;
> > fp1 z = &g; // error: type mismatch
> > }
> >
> > ----------
By the way, z should be an fp2 where the function differs only be return type.
My mistake.
> >
> > In other words, it must already look at x and y to find the address of the
> > correct f(). In the case of z, however, it must know the type of z and
> the,
> > specifically, the type of the return value of g() in order to raise a type
> > mismatch error.
>
> This example is much simpler to resolve than a function call, and will not
> lead to unexpected behaviour,
> as there is no implicit conversion and the compiler will tell you, if the
> complete types don't match.
This is a compile-time selection of several functions with the same name. Overl
oad resolution is exactly the same thing--a compile-time selection of several
functions with the same name. There is no run-time behavior here at all.
Overload resolution merely picks the function (at compile-time) and that *exact*
function is always called at run time (barring catastrophic failure). My point
with function pointers is that they use a *contextual* form of overload
resolution. Type-conversion has nothing to do with it. I'm merely pointing out
that compilers must already determine which function based on context. In the
case of function pointers and references, based entirely on context.
Assignment/initialization of function pointers and initialization of function
references *is* a compile-time overload resolution. How are these two much
different?
void g(double);
void g(int);
typedef void (&rg_dbl)(double);
rg_dbl g_ref = g; // compile-time overload resolution based on context
int main() {
g_ref(0.0);
g(0.0); // compile-time overload resolution based on parameter
return 0;
}
> If you have to resolve a function you don't have this guarantee as their is
> something like type-promotion and implicit type-conversion of arguments,
> which helps out to resolve those issues.
> And as I believe the current conversion rules are complex enough,
> and should not be made even more complex for a feature,
> we all most likely are better off without, seen in a broader perspective.
Or a lack of a broader perspective as the case may be. I'll give you an even
better example:
namespace A {
double f() {
std::cout << "double" << std::endl;
return 0.0;
}
}
namespace B {
int f() {
std::cout << "int" << std::endl;
return 0;
}
}
namespace C {
using namespace A; // necessary to get both f's into the same scope
using namespace B;
typedef double (*dbl_pf)();
typedef int (*int_pf)();
}
int main() {
C::dbl_pf x = &C::f;
C::int_pf y = &C::f;
(*x)();
(*y)();
return B::f();
}
This is an example of overload resolution with function pointers based entirely
on return type, which produces the output:
double
int
int
As it should. Whereas calling C::f directly would be ambiguous. The fact that
it is possible to "fake" overload by return type like this is another argument
that it should be generalized. In order to make C++ simpler and more general,
you have two options:
1. change the address-of-function syntax to include parameter types, which
would break millions of lines of code.
2. generalize context dependent overloading via return type, which is
considered only if parameter resolution is ambigious, which would break exactly
*zero* code.
In order to make C++ more general, *easier* to learn, more orthogonal, etc., the
only feasible option is #2, which would not be anymore complicated than
parameter resolution already is. There are times that you would have to be
explicit, just like with parameters, and there are many times that you would
not. Consider:
double f();
int f();
int g(double);
int g(int);
int main() {
double x = 1.0 + f();
x = 1.0 + static_cast<int>(f)();
int y = 0;
y = g(1.0 + g(static_cast<double>(y)));
return 0;
}
It seems to me that the only real difference is where the paranthesis and static
casts are, other than "bottom-up" resolution vs. context resolution (both of
which are already implemented in different mechanisms: function call vs.
function address).
The biggest reason of all:
double f(double, double);
int f(int, int); // you can have this
double f(double);
int f(int); // you can have this as well
double f();
int f(); // but you can't have this, despite an obvious and reasonable
progression
> > Therefore, if I has something slightly more convoluted:
[snip old example]
> The only difference to the preceding example, I can see, is that it is more
> intricately implemented, semantically seen though it appears to me as being
> the same.
It is the same thing, just slightly more complicated "context." Maybe I should
have made it more complicated:
typedef int (*fp1)(int);
typedef double (*fp2)(double);
int a_default_func(int arg);
double a_default_func(double arg);
fp1 _1a = &a_default_func, _1b = &a_default_func;
fp2 _2a = &a_default_func, _2b = &a_default_func;
inline fp1& select(int a) {
if (a) return _1a;
return _1b;
}
inline fp2& select(double a) {
if (a > 0.0) return _2a;
return _2b;
}
int a_func(int arg) { return arg; }
double a_func(double arg) { return arg; }
int main() {
double x = 0.0;
int y = 0;
// manipulate x and y for a while...
select(x) = &a_func;
select(y) = &a_func;
return (*_1a)(0);
}
This is just an example of contextual resolution, that's all. In this example
the type of the "expression" select(...) is slightly less obvious, which just
increases the context dependence somewhat, further pointing out the fact that
context is already used for resolution.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: news_comp.std.c++_expires-2001-09-01@nmhq.net (Niklas Matthies)
Date: Fri, 15 Jun 2001 16:28:22 GMT Raw View
On Fri, 15 Jun 2001 09:48:36 GMT, Samuel Schulman <s.schulman@berlin.de> =
wrote:
> "James Dennett" <jdennett@acm.org> wrote in message
> news:3B292C21.68867FD1@acm.org...
> > Samuel Schulman wrote:
> > > "Paul Mensonides" <pmenso57@home.com> wrote in message
> > > news:wpvV6.157904$p33.3303638@news1.sttls1.wa.home.com...
[=B7=B7=B7]
> > > > Therefore, in this example: sizeof(A) =3D=3D sizeof(get())
> > >
> > > The type of "get()" is not A.
> >
> > It seems to me that it is A. What else could it be? "get()" is
> > an expression (a function call) and it evaluates to an object of
> > type A.
>=20
> I am not sure, if you mean the type of the function 'get()' is A, than
> I can pretty sure say, that you cannot call the return type of a
> function as the type of the function itself, although it is part of
> the complete function type(ISO14882 8.3.5.4).
But the expression `get()' is (in this context) not a function, it's a
function call. And the type of a function call expression is the
(static) return type of the function called.
> Therefore the type of the function is 'A(*)(void)'.
No, that's a pointer-to-function type. The function type is `A()(void)'.
Consider:
typedef int (F)(); // function type
typedef int (*FP)(); // pointer-to-function type
typedef int (&FR)(); // reference-to-function type
=20
F foo; // forward-declare foo()
int foo() { return 42; }
FP fp =3D foo; // or: FP fp =3D &foo;
FR fr =3D foo;
int main()
{
fp(); // or: (*fp)();
fr();=20
sizeof(foo); // not legal: taking the size of a
// function type is not allowed
sizeof(fp); // ok: returns size of the function pointer
sizeof(fr); // again not legal: size of the function type
sizeof(foo()); // ok: returns size of int
sizeof(fp()); // ok: returns size of int
sizeof(fr()); // ok: returns size of int
}
-- Niklas Matthies
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Sat, 16 Jun 2001 00:33:44 GMT Raw View
>"Niklas Matthies" <news_comp.std.c++_expires-2001-09-01@nmhq.net> wrote in
message
news:slrn9ijtb5.2ef.news_comp.std.c++_expires-2001-09-01@ns.nmhq.net...
>On Fri, 15 Jun 2001 09:48:36 GMT, Samuel Schulman <s.schulman@berlin.de>
wrote:
> > "James Dennett" <jdennett@acm.org> wrote in message
> > news:3B292C21.68867FD1@acm.org...
> > > Samuel Schulman wrote:
> > > > "Paul Mensonides" <pmenso57@home.com> wrote in message
> > > > news:wpvV6.157904$p33.3303638@news1.sttls1.wa.home.com...
> >[ ]
> > > > > Therefore, in this example: sizeof(A) == sizeof(get())
> > > >
> > > > The type of "get()" is not A.
> > >
> > > It seems to me that it is A. What else could it be? "get()" is
> > > an expression (a function call) and it evaluates to an object of
> > > type A.
> >
> > I am not sure, if you mean the type of the function 'get()' is A, than
> > I can pretty sure say, that you cannot call the return type of a
> > function as the type of the function itself, although it is part of
> > the complete function type(ISO14882 8.3.5.4).
>
> But the expression `get()' is (in this context) not a function, it's a
> function call. And the type of a function call expression is the
> (static) return type of the function called.
>
> > Therefore the type of the function is 'A(*)(void)'.
>
> No, that's a pointer-to-function type. The function type is `A()(void)'.
I used this notation because I thought it would be clearer what I mean(And
thought a little bit to low-level).
I will be more carefull next time.
> Consider:
>
> typedef int (F)(); // function type
> typedef int (*FP)(); // pointer-to-function type
> typedef int (&FR)(); // reference-to-function type
>
> F foo; // forward-declare foo()
>
> int foo() { return 42; }
>
> FP fp = foo; // or: FP fp = &foo;
> FR fr = foo;
>
> int main()
> {
> fp(); // or: (*fp)();
> fr();
> sizeof(foo); // not legal: taking the size of a
> // function type is not allowed
> sizeof(fp); // ok: returns size of the function pointer
> sizeof(fr); // again not legal: size of the function type
> sizeof(foo()); // ok: returns size of int
> sizeof(fp()); // ok: returns size of int
> sizeof(fr()); // ok: returns size of int
> }
>
>
> -- Niklas Matthies
-Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Matthew Austern <austern@research.att.com>
Date: Sat, 16 Jun 2001 01:21:05 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> writes:
> int a_func(int arg) { return arg; }
> double a_func(double arg) { return arg; }
>
> int main() {
> double x = 0.0;
> int y = 0;
> // manipulate x and y for a while...
> select(x) = &a_func;
> select(y) = &a_func;
> return (*_1a)(0);
> }
>
> This is just an example of contextual resolution, that's all. In this example
> the type of the "expression" select(...) is slightly less obvious, which just
> increases the context dependence somewhat, further pointing out the fact that
> context is already used for resolution.
Yes. I regard this violation of the bottom-up principle as a wart,
and one that does sometimes cause problems. It's (barely) tolerable
because it's in a relatively minor corner of the language, and because
nobody has thought of a better way of dealing with what it means to
take the address of an overloaded name. I'd hate to see this wart
spread to the overload resolution rules.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Sat, 16 Jun 2001 12:01:29 GMT Raw View
In article <qucW6.171947$p33.3571677@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>2. generalize context dependent overloading via return type, which is
>considered only if parameter resolution is ambigious, which would break exactly
>*zero* code.
Sorry, but from my position you seem to want to special case the return
type, just differently from the current rules. If we were to overload
on return value it would just have to be treated like the zeroeth
parameter. Else consider the reaction of a normally sane programmer to:
class X;
X& foo(long);
int foo(int);
int main(){
X x=foo(2); // no overload matches return type
...
}
Because by your rules foo(2) unambiguously requires foo(int) to be
called despite the fact that a simple promotion would allow foo(long) to
be chosen.
Simply put, if we overload on return type, it has to have equal status
with the parameters. Now I agree we could have designed C++ that way,
but we did not and the cost of changing it that way seems to high and
there seems no logic to changing it any other way.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Sat, 16 Jun 2001 12:02:14 GMT Raw View
"Matthew Austern" <austern@research.att.com> wrote in message
news:dilsnh1r1ln.fsf@isolde.research.att.com...
> "Paul Mensonides" <pmenso57@home.com> writes:
>
> > int a_func(int arg) { return arg; }
> > double a_func(double arg) { return arg; }
> >
> > int main() {
> > double x = 0.0;
> > int y = 0;
> > // manipulate x and y for a while...
> > select(x) = &a_func;
> > select(y) = &a_func;
> > return (*_1a)(0);
> > }
> >
> > This is just an example of contextual resolution, that's all. In this
example
> > the type of the "expression" select(...) is slightly less obvious, which
just
> > increases the context dependence somewhat, further pointing out the fact
that
> > context is already used for resolution.
>
> Yes. I regard this violation of the bottom-up principle as a wart,
> and one that does sometimes cause problems. It's (barely) tolerable
> because it's in a relatively minor corner of the language, and because
> nobody has thought of a better way of dealing with what it means to
> take the address of an overloaded name. I'd hate to see this wart
> spread to the overload resolution rules.
This is only a wart when compared to normal overload resolution. However, C++
is full of such context dependant situations. The fact that this is an
exception to the current resolution does not make it bad, it just makes it
stylistically different. The fact that context resolution already exists is one
of the main reasons why it should be generalized so that it is no longer an
"exception to the rule." I disagree that this is just a "minor" part of the
language; that depends entirely on how and to what extent that it is used.
There is a good reason that C++ has its low level core; it is often used for low
level programming. The ideal of single-pass bottom-up traversal is impractical
in many situations anyway, and I disagree that this can be used exclusively as
an argument against a feature. The usefulness for a *user* of a language, the
efficiency of the mechanism, and the generality and orthogonality of the feature
is significantly more important than the ease of implementation. In this case,
particularly, the difficulty of implementation would be relatively minor.
Overload resolution only *seems* like it is complicated, but those people that
want to and are willing to learn can do so fairly easily. Also, when in doubt,
consult the rules, as they are fairly straight forward.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Wed, 13 Jun 2001 16:20:44 GMT Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message
news:24JYSBCGPrJ7EwJ5@ntlworld.com...
> In article <sswV6.158121$p33.3307749@news1.sttls1.wa.home.com>, Paul
> Mensonides <pmenso57@home.com> writes
> >I have stated repeatedly that I think return type resolution should only be
> >invoked when parameter resolution is ambiguous,
>
> Sorry, I missed that. The result of following that line would have so
> little utility as to be not worth the time taken discussing it. BTW, did
> you mean ambiguity or two functions whose only difference was in their
> return type?
No, I mean two functions where the call cannot be resolved via all the normal
parameter resolution rules. I disagree that this would have very little
utility. Maybe in extremely convoluted cases of overloading, but not in general
usage. I do agree that this is not a *necessary* extension in that it has no
inherent functionality of its own, though that line is somewhat blurred by the
use of templates. Nevertheless, this is an inconsistency in the language, and
that is the primary reason that I would like to see it, but I also can imagine
valid uses of simple return type overloading for functions that require no
parameters or parameters that are all identical, etc.. Whether or not this type
of mechanism can be misused is irrelevent compared to whether it *can* be used
well. Accordingly, I would like to see a general mechanism for return type
overloading without parameter strictures or anything like that, yet one that
only performs this type of resolution when parameter resolution is
ambiguous--which is well suited to preserving legacy code.
Of course, we should focus on what everyone knows is really important: the
email address-of operator...
bool Paul::operator@(const Domain&);
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Wed, 13 Jun 2001 16:20:37 GMT Raw View
remove.haberg@matematik.su.se (Hans Aberg) writes:
| So if C++ compilers generally are not shipped with any such type inference
| tools, then that probably sets a limit on how advanced the C++ type system
| can be.
I think the goal isn't to have the most advanced type system. It is
about of having a useful type system which can assist the
programmer in practical situation. Does not having overloading on
return type really makes difficult the job of writing practical programs?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Wed, 13 Jun 2001 16:20:56 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> writes:
| "Bjarne Stroustrup" <bs@research.att.com> wrote in message
| news:GEsFCA.2Jv@research.att.com...
| > Article 52158 of comp.std.c++:
| > The reason that C++ doesn't support overloading based on the return type
| > is not that I didn't know how to implement it or that I feared compile-time
| > overheads. The reason is that I was confident that often the results would be
| > incomprehensible to programmers, and specifically that I wanted to preserve
| > the nice property that the meaning of expressions can be determined from
| > the bottom up. For example, once you know the types of x and y, the legality
| > and meaning (if any) of x+y can be determined.
|
| What about the contrary, yet similar example of function pointers, where it must
| use the return type to correctly address the function:
|
| typedef int (*fp)(double);
|
| void f(double);
|
| void h() {
| fp = &f; // type mismatch
But overloading has nothing to do here.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 13 Jun 2001 16:24:58 GMT Raw View
In article <dily9qxwiht.fsf@isolde.research.att.com>, Matthew Austern
<austern@research.att.com> wrote:
>bs@research.att.com (Bjarne Stroustrup) writes:
...
>> I still think that the advantages of *not* overloading on the return type
>> outweighs the advantages of overloading on the return type.
>
>I agree. And as an illustration of Bjarne's point, consider the one
>place in C++ that doesn't follow the bottom-up rule: taking the
>address of an overloaded function, where the return type is context
>dependent.
...
> I believe that this
>context dependence does sometimes cause real confusion.
I am not sure what kind of return type context dependencies you have in
your mind. Could you please give an example?
> The rules are complicated, and interact in unexpected ways
>with other language features (such as templates).
...
> I'd hate to
>see these problems extended from a relatively minor part of the
>language to much more general features.
There are two issues here I believe, the possibility to find a good
implementation into the compilers, and how practical it will be too the
programmer.
As for the implementation, it seems that types can be resolved by simple
Prolog programs. For example, if one has the C++ example
a f() { ... }
b f() { ... }
int x = f() + f();
then type overloading can be solved by the following Prolog program:
f(a, void).
f(b, void).
add(int, a, a).
add(int, b, b).
expr(X, Y) :- f(X, void), f(Y, void), add(int, X, Y).
The first argument of a Prolog head is the function return type; the rest
are the function arguments. The connection between types in an expression
is built up by clauses.
Then the possible types can be found by
?- expr(X, Y).
X = a
Y = a;
X = b
Y = b.
Since the answer was not unique, where have an ambiguity here.
So it seems that when adding template arguments, one gets some
generalization dependent on unification, as in Hindley-Milner type
systems.
bs@research.att.com (Bjarne Stroustrup) wrote:
>> I think that finding a good implementation for a full scale overloading by
>> return type will be a problem, as one will have to combine type inference
>> from the two ends of the expression type tree.
>
>Good algorithms for that have been known for at least 20 years. Look at
>the Ada implementation literature. In particular, look for something called
>"the yo-yo algorithm".
So is that what those algorithms do?
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Matthew Austern <austern@research.att.com>
Date: Wed, 13 Jun 2001 18:12:29 GMT Raw View
remove.haberg@matematik.su.se (Hans Aberg) writes:
> In article <dily9qxwiht.fsf@isolde.research.att.com>, Matthew Austern
> <austern@research.att.com> wrote:
>
> >bs@research.att.com (Bjarne Stroustrup) writes:
> ...
> >> I still think that the advantages of *not* overloading on the return type
> >> outweighs the advantages of overloading on the return type.
> >
> >I agree. And as an illustration of Bjarne's point, consider the one
> >place in C++ that doesn't follow the bottom-up rule: taking the
> >address of an overloaded function, where the return type is context
> >dependent.
> ...
> > I believe that this
> >context dependence does sometimes cause real confusion.
>
> I am not sure what kind of return type context dependencies you have in
> your mind. Could you please give an example?
I didn't mean anything very profound. Just that if you have
void f(int);
void f(double);
then it is legal to write "&f", but it is impossible to tell
what the type of "&f" is without looking at the context. A
human reader can't do bottom-up analysis in this case.
I think of this as a wart, and there are cases where it causes
problems. I wouldn't like to see more constructs that violate
the bottom-up principle.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Wed, 13 Jun 2001 18:12:59 GMT Raw View
In article <fl66e0hmvt.fsf@jambon.cmla.ens-cachan.fr>, Gabriel Dos Reis
<dosreis@cmla.ens-cachan.fr> wrote:
>| So if C++ compilers generally are not shipped with any such type inference
>| tools, then that probably sets a limit on how advanced the C++ type system
>| can be.
>
>I think the goal isn't to have the most advanced type system. It is
>about of having a useful type system which can assist the
>programmer in practical situation. Does not having overloading on
>return type really makes difficult the job of writing practical programs?
As you say, the main point is that the type system supports the programmer
in endeavors.
As for the type inference tool, that is used to help people programming
with polymorphic types (and not overloading by return type), and C++
already has a primitive form of the latter in the form of templates. And
the point with this kind of generalities is that it is more structured,
which is better for humans, and that it also decreases programming time,
as one can write programs with greater generality and then specialize.
As for the overloading by return type, I do not know other than some like
that feature. If it fits into a bigger scheme, perhaps it comes a long as
a result of that bigger scheme.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: markw65@my-deja.com (Mark Williams)
Date: Wed, 13 Jun 2001 21:44:24 GMT Raw View
Matthew Austern <austern@research.att.com> wrote in message news:<dilu21kmg7q.fsf@isolde.research.att.com>...
> remove.haberg@matematik.su.se (Hans Aberg) writes:
>
> I didn't mean anything very profound. Just that if you have
> void f(int);
> void f(double);
>
> then it is legal to write "&f", but it is impossible to tell
> what the type of "&f" is without looking at the context. A
> human reader can't do bottom-up analysis in this case.
>
> I think of this as a wart, and there are cases where it causes
> problems. I wouldn't like to see more constructs that violate
> the bottom-up principle.
I think of it as implicit type-coercion. The type of "f" is
overloaded-function. It can be implicitly converted to
pointer-to-function-with-type-of-one-of-its-overloads in any context
where that type is required. (yes, Im aware the standard doesnt
describe it that way).
How is this different from, say, 0 being converted to a null pointer
when needed? Or char being converted to int for that matter.
Mark Williams
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Wed, 13 Jun 2001 22:01:37 GMT Raw View
markw65@my-deja.com (Mark Williams) writes:
[...]
| How is this different from, say, 0 being converted to a null pointer
| when needed?
And that feature isn't something I'm particulary found of; so I'm not
convinced at all that we should propagate similar constructs over the
language. Current overload resolution rules are complex enough.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Thu, 14 Jun 2001 13:12:46 GMT Raw View
In article <dilu21kmg7q.fsf@isolde.research.att.com>, Matthew Austern
<austern@research.att.com> wrote:
>> I am not sure what kind of return type context dependencies you have in
>> your mind. Could you please give an example?
>
>I didn't mean anything very profound. Just that if you have
> void f(int);
> void f(double);
>
>then it is legal to write "&f", but it is impossible to tell
>what the type of "&f" is without looking at the context. A
>human reader can't do bottom-up analysis in this case.
>
>I think of this as a wart, and there are cases where it causes
>problems. I wouldn't like to see more constructs that violate
>the bottom-up principle.
It is clear such type theory additions cause more ambiguities to happen.
And when an ambiguity does happen, the programmer should be able to
understand why it happened. And if the ambiguity was not the cause of
something semantically wrong with the program, then one should ideally be
able to somehow resolve the ambiguity -- otherwise one will end up trying
to program around the type systems that was intended to help you.
As for the overloading by return type, if the implementation depends on
Prolog like programs and not the simple argument-to-return type resolving
method, then it might be difficult for the programmer to resolve the cause
of the ambiguities in the head. So this calls for some improved tools to
support the programmer.
Perhaps this speaks against the overloading by return type feature. But on
the other hand the template system already makes the C++ types system so
complicated that it perhaps is in the need of better type system tools
anyway:
I noticed this when I translated a snippet of Haskell code into C++ (the
Mini-Prolog that comes with Hugs): I part because I wanted to learn the
differences between Haskell and C++, I decided to make the C++ code as low
level as possible, which of course causes problems if the Haskell
constructing calls for the construction for covers. If the covers then are
static in nature, one can try making use of the template system. And what
I found that sometimes it was tricky to pick the C++ types together this
way.
[So this might be another topic for the C++ standard: Better support for
building static (C++ compile time) covers. The Haskell compiler GHC writes
C as output, and the idea would be to make it simpler for such compilers
to write C++ as output. Then as much as possible of the output should be
static for performance reasons.]
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Thu, 14 Jun 2001 17:10:07 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:wpvV6.157904$p33.3303638@news1.sttls1.wa.home.com...
>
> "Samuel Schulman" <s.schulman@berlin.de> wrote in message
> news:TrOU6.2282$35.1905982@typhoon.san.rr.com...
>
> [snip]
>
> > I am really having a hard time to understand the coherence between the
> > sizeof operator
> > and the 'overloading by return value', and how the mechanism to support
> > overloading, based on return type, does already exists?
>
> sizeof must evaluate the "type" of an expression in order to discover its
size.
You should read in the ISO14882, 5.3.3 about the operator sizeof,
and you will find out that the expression is not evaluated.
[whereas in ISO9899 C there is an exception]
> For example,
> if I have a function that returns a struct with two ints:
>
> ----------
>
> struct A {
> int x, y;
> A(int p, int q) : x(p), y(q) { return; }
> };
>
> A get() {
> return A(0, 0);
> }
>
> ----------
>
> and then I pseudo-call that function:
>
> ----------
>
> void f() {
> std::size_t s = sizeof(get());
> }
>
> ----------
>
> sizeof must determine that the type of "get()" is "A" and return the size
of A.
> Therefore, in this example: sizeof(A) == sizeof(get())
The type of "get()" is not A.
You might can call A, as sometimes reffered to, the value of the function,
but not the type.
> the backend of sizeof (i.e. type determination) is all that is necessary
in
> order to determine the "context" of a function call that is overloaded via
> return type.
>
> Furthermore, this same type of mechanism is used with function pointers.
In
> order to select the correct overload of a function, it uses the type of
function
> pointer that is being assigned to.
As sizeof works different than you explained, it cannot be the same.
> ----------
>
> void f();
> void g(double);
> int f(double);
>
> typedef void (*fp1)();
> typedef int (*fp2)(double);
>
> void h() {
> fp1 x = &f;
> fp2 y = &f;
> fp1 z = &g; // error: type mismatch
> }
>
> ----------
>
> In other words, it must already look at x and y to find the address of the
> correct f(). In the case of z, however, it must know the type of z and
the,
> specifically, the type of the return value of g() in order to raise a type
> mismatch error.
This example is much simpler to resolve than a function call, and will not
lead to unexpected behaviour,
as there is no implicit conversion and the compiler will tell you, if the
complete types don't match.
If you have to resolve a function you don't have this guarantee as their is
something like type-promotion and implicit type-conversion of arguments,
which helps out to resolve those issues.
And as I believe the current conversion rules are complex enough,
and should not be made even more complex for a feature,
we all most likely are better off without, seen in a broader perspective.
> Therefore, if I has something slightly more convoluted:
>
> ----------
>
> typedef int (*fp2)(double);
>
> fp2 g_a = NULL, g_b = NULL;
>
> fp2& select(int a) {
> if (a == 0) return g_a;
> return g_b;
> }
>
> int a_func(double);
> void a_func(void);
>
> void f() {
> select(0) = &a_func;
> return;
> }
>
> ----------
>
> Here, the mechanism that sizeof uses must determine that the type of
"select(0)"
> is "fp2&" and therefore assign the address of the appropriate a_func().
In
> other words, it is performing overload resolution partially with the
return
> type, since, if the return types don't match, it is an error.
The only difference to the preceding example, I can see, is that it is more
intricately implemented, semantically seen though it appears to me as being
the same.
> Paul Mensonides
>
- Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Marcin 'Qrczak' Kowalczyk" <qrczak@knm.org.pl>
Date: Thu, 14 Jun 2001 17:25:56 GMT Raw View
Wed, 13 Jun 2001 22:01:37 GMT, Gabriel Dos Reis <dosreis@cmla.ens-cachan.=
fr> pisze:
> | How is this different from, say, 0 being converted to a null pointer
> | when needed?=20
>=20
> And that feature isn't something I'm particulary found of;
But would you want the type of a pointer to be explicit in a null
pointer constant?
--=20
__("< Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
\__/
^^ SYGNATURA ZAST=CAPCZA
QRCZAK
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 11 Jun 2001 21:56:29 GMT Raw View
In article <10f784d5.0106111057.565997a2@posting.google.com>,
markw65@my-deja.com (Mark Williams) wrote:
>> So what you propose is evidently to make worse the problems that people
>> want to alleviate; I mean, if you really mean that it is OK to add just
>> any amount of ambiguities that makes real life C++ programming more
>> difficult.
>
>I dont propose anything. I merely refuted your claim that your example
>would cause problems for compilers.
I am not sure what you mean: It is already causing a problem for
compilers. The problems will grow worse with more complicated example
expressions, resulting in a slow compiler.
>> What kind of type inference system do you propose, that is, what does the
>> theory look like, and how is it implemented in a compiler?
>
>Implementing it is not a problem. Compilers already have to do this
>for conversion operators, and for overloaded pointer to functions.
I think that finding a good implementation for a full scale overloading by
return type will be a problem, as one will have to combine type inference
from the two ends of the expression type tree.
So if you say that implementation is not a problem, I say I believe it
when I see it. :-)
> I
>think the real answer is what you have stated above - most experts
>agree that its a bad thing.
Circular structures in the type system, yes.
As for other type system extensions, I think that one will have to have a
good type theory with algorithms.
If you really are into this game of overloading by return type, why not
make an experimental implementation of just the type system (remark not
intended as a taunt): Hindley-Milner type systems makes use of
unification, and I just translated the Mini-Prolog that comes with Hugs
http://haskell.org/hugs into C++:
I use it for experimentation with CLP style implementation, but it ought
be possible to make mini-C++ type systems that tells what is possible, if
now unification is what one want to make use of.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Tue, 12 Jun 2001 21:07:40 GMT Raw View
In article <GEsFCA.2Jv@research.att.com>, bs@research.att.com (Bjarne
Stroustrup) wrote:
>The reason that C++ doesn't support overloading based on the return type
>is not that I didn't know how to implement it or that I feared compile-time
>overheads. The reason is that I was confident that often the results would be
>incomprehensible to programmers, and specifically that I wanted to preserve
>the nice property that the meaning of expressions can be determined from
>the bottom up. For example, once you know the types of x and y, the legality
>and meaning (if any) of x+y can be determined.
I have myself no preference for or against the overloading by return type:
A few years ago, I found the feature interesting as a possible extension
to C++, but later I have not missed not having it.
>From the general point of view, if a more general type system is possible,
and especially if there is no burden on the compiler efficiency, why not?
If a type system produces a lot of ambiguities that cannot be resolved,
that surely will produce hard times for the programmers.
A more general type system probably requires better programming tools: For
example, Haskell, which uses a Hindley-Milner like type system, is quite
difficult to use, but the Hugs interpreter has a type inference feature
that allows one to plug in an expression and get its polymorphic type.
This can then be plugged into the program if one so like.
So if C++ compilers generally are not shipped with any such type inference
tools, then that probably sets a limit on how advanced the C++ type system
can be.
As for the property that the type inference moves the opposite direction
of the normal function computational order, from the returns towards the
arguments, I intuitively find that somewhat fishy. But some may like that.
I also saw an application of it:
In a C++ wrap of the GMP (Gnu Multi-Precision numerical library): One
wants the arbitrary floating precision of an expression to be set by the
return precision. This was achieved by some exceptional C++ template
tweaking.
When I analyzed the floating point precision problem, I found another
mathematical solution: To set the floating point precision of an
expression by precision formulas based on logarithmic differentials. Then
one should be able to achieve arbitrary floating point precision that
behaves normally in the sense that all computations, including the
precision estimates, flow from the arguments towards the returns. And then
the type inference flowing from the return type towards the arguments
would not be needed.
Even though I feel that this solution is more mathematically sound, I
could still not say that the other solution, where type inference seems to
flow from the return type towards the arguments, will not be useful to
programmers.
But as far as I myself am concerned, I will probably try to avoid
solutions that depend on a flow from the return towards the arguments
(even though I heavily makes use of a dynamic version, "double dispatch"
on a polymorphic variable, doing just that).
But on the same time I cannot say that the overloading by return type
feature will not be useful to other programmers.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 12 Jun 2001 21:07:57 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:TrOU6.2282$35.1905982@typhoon.san.rr.com...
[snip]
> I am really having a hard time to understand the coherence between the
> sizeof operator
> and the 'overloading by return value', and how the mechanism to support
> overloading, based on return type, does already exists?
sizeof must evaluate the "type" of an expression in order to discover its size.
For example,
if I have a function that returns a struct with two ints:
----------
struct A {
int x, y;
A(int p, int q) : x(p), y(q) { return; }
};
A get() {
return A(0, 0);
}
----------
and then I pseudo-call that function:
----------
void f() {
std::size_t s = sizeof(get());
}
----------
sizeof must determine that the type of "get()" is "A" and return the size of A.
Therefore, in this example: sizeof(A) == sizeof(get())
the backend of sizeof (i.e. type determination) is all that is necessary in
order to determine the "context" of a function call that is overloaded via
return type.
Furthermore, this same type of mechanism is used with function pointers. In
order to select the correct overload of a function, it uses the type of function
pointer that is being assigned to.
----------
void f();
void g(double);
int f(double);
typedef void (*fp1)();
typedef int (*fp2)(double);
void h() {
fp1 x = &f;
fp2 y = &f;
fp1 z = &g; // error: type mismatch
}
----------
In other words, it must already look at x and y to find the address of the
correct f(). In the case of z, however, it must know the type of z and the,
specifically, the type of the return value of g() in order to raise a type
mismatch error.
Therefore, if I has something slightly more convoluted:
----------
typedef int (*fp2)(double);
fp2 g_a = NULL, g_b = NULL;
fp2& select(int a) {
if (a == 0) return g_a;
return g_b;
}
int a_func(double);
void a_func(void);
void f() {
select(0) = &a_func;
return;
}
----------
Here, the mechanism that sizeof uses must determine that the type of "select(0)"
is "fp2&" and therefore assign the address of the appropriate a_func(). In
other words, it is performing overload resolution partially with the return
type, since, if the return types don't match, it is an error.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 12 Jun 2001 21:20:32 GMT Raw View
"Bjarne Stroustrup" <bs@research.att.com> wrote in message
news:GEsFCA.2Jv@research.att.com...
> Article 52158 of comp.std.c++:
> The reason that C++ doesn't support overloading based on the return type
> is not that I didn't know how to implement it or that I feared compile-time
> overheads. The reason is that I was confident that often the results would be
> incomprehensible to programmers, and specifically that I wanted to preserve
> the nice property that the meaning of expressions can be determined from
> the bottom up. For example, once you know the types of x and y, the legality
> and meaning (if any) of x+y can be determined.
What about the contrary, yet similar example of function pointers, where it must
use the return type to correctly address the function:
typedef int (*fp)(double);
void f(double);
void h() {
fp = &f; // type mismatch
}
Paul Mensonides
> I still think that the advantages of *not* overloading on the return type
> outweighs the advantages of overloading on the return type.
I think that we kind of have it both ways already with functions vs. function
pointers, which is worse than an orthogonal approach either way. I'm not even a
big fan of this because overloading is completely non-functional anyway.
However, I would like one of these two things:
return type overloading
-or-
parameter specification in a function pointer assignment:
(i.e. fp = &f(double), or something similer (yes, I realize there are problems
with this syntax))
On a related "orthogonal" issue, we have references to functions but not
references to member functions. Why?
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Mon, 11 Jun 2001 11:26:34 GMT Raw View
"Jay Levitt" <jaythemailguy@aol.com> wrote in message
news:MPG.1587a9d646ac710e989687@news-central.giganews.com...
> In article <JbhT6.1185$Lz4.645539@typhoon.san.rr.com>,
s.schulman@berlin.de
> says...
> > double f(double){ }
> > int f(int){ }
> >
> > main(){
> > short s = 0;
> > double d = foo(s);
> > }
> >
> > Which function should be used?
> > f(int) seemed to be the better candidate because of the argument-type,
but
> > f(double) has the better fitting return type, so which function should
be
> > used?!
> >
>
> How does this differ from...
>
> void f(double, double) { }
> void f(int, int) { }
>
> main(){
> short s = 0;
> double d = 0;
> f(d, s);
> }
Viewing it independently maybe not.
Yet you example shows, that it is enough that we have to resolve arguments,
as well resolving the function call by return value, appears to me is a
potential candidate for errors and confusion.
You will have code that will start to look like the following example, if
you have to resolve ambiguity for the arguments and the function value, and
then appears another question, what should have higher precedence?!
void f(double, double) { }
void f(int, int) { }
double f(int, double){}
main(){
short s = 0;
double d = 0;
double rd = static_cast<double>(f(static_cast<int>(d), s));
// does not appear very elegant to me
// and even more important which function should be
called now???
}
I don't think that this will do much good, and the gain won't be
substantial(or even non at all), but I believe it will introduce many errors
and a lot of confusion.
As well I think, if you need the semantics of 'overloading by return value'
,
you can use the return value as part of the parameter list.
-Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Mon, 11 Jun 2001 11:27:40 GMT Raw View
In article <rqEU6.137943$p33.2976438@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>I do not think that the committee does not listen. I think that the committee
>tends to over-exaggerate the complexity or "danger" of a given feature. Often,
>it then is considered wrong or "half-baked" based entirely on those ideas and a
>few toy examples. Granted, this is not always the case. I am not even a huge
>proponent of return type overloading. I'm merely pointing out that it is not
>significantly different than parameter overloading, and that it would be a nice
>feature for the sake of orthogonality and that the required mechanism is already
>mostly implemented via sizeof and function pointers.
Do you write compilers? Do you write programs with 1MLOC+ I suspect that
if you did either of those things you might have a different
perspective.
Now as to overload resolution, currently we have a set of rules that is
complicated enough that some already get unexpected results. Once you
throw return type into the mix I think you have broken the camel's back.
Whether you approve or not, many people rely on implicit conversions
both for parameters and for acquisition of return values. I would like
to see implicit narrowing conversions tackled, but I think they are so
deeply ingrained in much legacy code that the best we can hope for is
QoI generated diagnostics. Widening conversions do not seem to be a
problem, and I certainly would prefer to rely on them as opposed to
using an explicit cast.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 11 Jun 2001 11:28:07 GMT Raw View
In article <rqEU6.137943$p33.2976438@news1.sttls1.wa.home.com>, "Paul
Mensonides" <pmenso57@home.com> wrote:
>> If the compiler has to support overloading by return type, I pay for it
>> in increased complexity of the compiler and in its inability to detect
>> some types of error.
...
>Insignificant increased complexity, nor does this preclude diagnostic warnings.
I think that one might get a significant compiler performance hit:
In the regular type inference, one simply works from the argument types
towards the return types. Now you combine that with a process working the
other direction.
Think of the nested types of an expression with functions in it as a tree.
The original method works from the leaves towards the root, whereas you
want to combine it with a method going the other direction.
It is not going to be deterministic unless you (or someone) comes up with
a good algorithm.
And if it is not deterministic, that translates into being slow.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Mon, 11 Jun 2001 17:01:08 GMT Raw View
In article <Y2mzhiA9JVI7EwlO@ntlworld.com>, Francis Glassborow
<francisG@robinton.demon.co.uk> wrote:
>>No, I'm not. You don't pay for what you don't use. You don't have to use
>>overloading by return type if you don't want to.
>
>If the compiler has to support overloading by return type, I pay for it
>in increased complexity of the compiler and in its inability to detect
>some types of error.
If right should be right, I think that the C++ dogma "don't pay for what
you don't use" means that the runtime program should not pay in
performance for features added to C++ which are not used by the program.
(For example, a program which does not use RTTI at all should not be
slowed down by the fact that RTTI has been added to C++.)
However, it does not mean there are other costs, such as difficulty in
implementing a feature in a compiler and increased difficulty in
programming the language.
If one does not have a good theory for the type system, it will be
difficult to implement that in the compiler, and if the type system
produces a lot of ambiguities, it becomes difficult to program.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Mon, 11 Jun 2001 17:06:05 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> wrote in message
news:rpwT6.120257$p33.2525795@news1.sttls1.wa.home.com...
>
> "Samuel Schulman" <s.schulman@berlin.de> wrote in message
> news:qchT6.1186$Lz4.645683@typhoon.san.rr.com...
> > "Paul Mensonides" <pmenso57@home.com> wrote :
> > > The implementation for overloading based on return type is pretty much
> > already
> > > there in sizeof and function pointers. Consider:
> > >
> > > typedef void (*pf)();
> > > typedef int (*pf2)(int);
> > >
> > > void f();
> > > int f(int);
> > >
> > > void g() {
> > > pf a = &f;
> > > pf2 b = &f;
> > > }
> > >
> > > Which "f" is already based on the context of the expression on the
left
> > (which
> > > sizeof is already required to be able to figure out the type of
anyway).
> >
> > I am not quite sure what you mean, when you refer to the sizeof
operator.
> > And if I am not mistaken nothing equivalently exists what would have to
do
> > with function pointers.
> > The example shown does not use 'overloading by return type', the
function
> > pointers are assigned to the function which matches the type of the
pointer.
>
> sizeof() must evaluate (at compile time) the "type" of an expression in
order to
> determine its size. The mechanism behind sizeof() can figure out the
context
> for overloading based on return type. In the example above, C++ already
> requires a decision between which "f" based on the context of expression
in
> which it is involved. That decision is really no different than
overloading
> based on return type. Of course, the example doesn't use overloading
based on
> return type. I'm just saying that C++ already requires a contextual
analysis
> and the mechanisms to support overloading based on return type are already
> there--just not implemented for this specifically.
I am really having a hard time to understand the coherence between the
sizeof operator
and the 'overloading by return value', and how the mechanism to support
overloading, based on return type, does already exists?
> > >That
> > > is not a whole lot different than this:
> > >
> > > void f();
> > > int f(int);
> > > int f();
> > >
> > > void g() {
> > > int x = f();
> > > }
> >
> > I actually believe, that this is very different.
>
> How so? Obviously, one is function pointer assignment, and the other is a
> function call. But I'm not talking about the semantics of the example.
I'm
> talking about the deduction necessary to discover "which f()."
>
> Paul Mensonides
>
Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: markw65@my-deja.com (Mark Williams)
Date: Mon, 11 Jun 2001 19:08:05 GMT Raw View
remove.haberg@matematik.su.se (Hans Aberg) wrote in message news:<remove.haberg-0906010014080001@du129-226.ppp.su-anst.tninet.se>...
> In article <10f784d5.0106080730.6351ac0a@posting.google.com>,
> markw65@my-deja.com (Mark Williams) wrote:
> >And yet C++ already handles this...
> >
> >class A { ... };
> >class B { ... };
> >
> >int operator+(const A&, const A&);
> >int operator+(const B&, const B&);
> >
> >class f {
> >public:
> > operator A();
> > operator B();
> >};
> >
> >int g() {
> > int n = f() + f();
> > return n;
> >}
> >
> >Now of course, in this particular case, it fails to compile due to
> >ambiguity; but remove one of the operator + definitions, and it will
> >compile.
>
> The original C types have circular type conversions, and one can create
> such circular type conversions in C++ using A::operator B() type
> conversion.
>
> But most seems to agree that one would have been better off without the
> original C circular type conversions, and that one should avoid using them
> in C++ programming as much as possible. -- A::operator B() are only there
> to handle cases where there are no better solutions. The rule is, if you
> can avoid A::operator B() type conversions, don't use them.
>
> >What problems do you think your example exhibits that are not already
> >present in the language?
>
> So what you propose is evidently to make worse the problems that people
> want to alleviate; I mean, if you really mean that it is OK to add just
> any amount of ambiguities that makes real life C++ programming more
> difficult.
I dont propose anything. I merely refuted your claim that your example
would cause problems for compilers.
>
> But I think the real problem one will hit when trying to implement
> overloading by return type is that one has to make the type inference from
> the other end, from the returns towards the arguments, and combine that
> with the already present type inference, which goes from the arguments
> towards the returns.
>
> What kind of type inference system do you propose, that is, what does the
> theory look like, and how is it implemented in a compiler?
Implementing it is not a problem. Compilers already have to do this
for conversion operators, and for overloaded pointer to functions. I
think the real answer is what you have stated above - most experts
agree that its a bad thing.
Mark Williams
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Matthew Austern <austern@research.att.com>
Date: Tue, 12 Jun 2001 22:24:36 GMT Raw View
bs@research.att.com (Bjarne Stroustrup) writes:
> The reason that C++ doesn't support overloading based on the return type
> is not that I didn't know how to implement it or that I feared compile-time
> overheads. The reason is that I was confident that often the results would be
> incomprehensible to programmers, and specifically that I wanted to preserve
> the nice property that the meaning of expressions can be determined from
> the bottom up. For example, once you know the types of x and y, the legality
> and meaning (if any) of x+y can be determined.
>
> I still think that the advantages of *not* overloading on the return type
> outweighs the advantages of overloading on the return type.
I agree. And as an illustration of Bjarne's point, consider the one
place in C++ that doesn't follow the bottom-up rule: taking the
address of an overloaded function, where the return type is context
dependent. The rules are complicated, and interact in unexpected ways
with other language features (such as templates). I believe that this
context dependence does sometimes cause real confusion. I'd hate to
see these problems extended from a relatively minor part of the
language to much more general features.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 12 Jun 2001 22:25:32 GMT Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message
> Do you write compilers? Do you write programs with 1MLOC+ I suspect that
> if you did either of those things you might have a different
> perspective.
No, but I do write parsers and editors. By the way, do you habitually use the
global namespace?
> Now as to overload resolution, currently we have a set of rules that is
> complicated enough that some already get unexpected results. Once you
> throw return type into the mix I think you have broken the camel's back.
With the type of attitude that you have, you would never have endorsed function
overloading in the first place. This is *not* more complicated. If parameter
resolution fails, resolve on return type. As a matter of fact, resolving on
return type would be much simpler than the comparable parameter resolution.
> Whether you approve or not, many people rely on implicit conversions
> both for parameters and for acquisition of return values. I would like
> to see implicit narrowing conversions tackled, but I think they are so
I don't disagree with implicit conversions (except narrowing built-in ones). I
do, however, think that they should be relied on infrequently since the can be
worse than casts for someone following the code.
> deeply ingrained in much legacy code that the best we can hope for is
> QoI generated diagnostics. Widening conversions do not seem to be a
> problem, and I certainly would prefer to rely on them as opposed to
> using an explicit cast.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 12 Jun 2001 22:30:52 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:aUBU6.2126$35.1602049@typhoon.san.rr.com...
[snip]
> Viewing it independently maybe not.
>
> Yet you example shows, that it is enough that we have to resolve arguments,
> as well resolving the function call by return value, appears to me is a
> potential candidate for errors and confusion.
> You will have code that will start to look like the following example, if
> you have to resolve ambiguity for the arguments and the function value, and
> then appears another question, what should have higher precedence?!
>
> void f(double, double) { }
> void f(int, int) { }
> double f(int, double){}
>
> main(){
> short s = 0;
> double d = 0;
> double rd = static_cast<double>(f(static_cast<int>(d), s));
> // does not appear very elegant to me
> // and even more important which function should be
> called now???
> }
I have stated repeatedly that I think return type resolution should only be
invoked when parameter resolution is ambiguous, which renders this example moot,
as it would be a semantic error. Since matching by promotion resolves before
standard conversions, void f(int, int) would be selected via normal parameter
overloading. Assigning a "void" to a double is a semantic error, as there is no
conversion from "void" to double (with or without static_cast or C-style casts),
and would not compile.
In extreme cases, manual resolution would be necessary, but it would not be any
dirtier than manual resolution of parameters.
double f();
float f();
double rd = static_cast<float>(f());
Alternately, you could enhance the syntax to remove so many nested parenthesis
and separate the normal casting mechanism.
double rd = static_cast<float>(f)();
This way, "static_cast<float>(f)" returns either a function reference or the
psuedo-type that is returned from dereferencing a function pointer (*fp). In
the case of a member function it would return the closure that (obj.*mfp)typ
returns.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 13 Jun 2001 01:13:32 GMT Raw View
In article <PxvV6.157944$p33.3304162@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>With the type of attitude that you have, you would never have endorsed function
>overloading in the first place. This is *not* more complicated. If parameter
>resolution fails, resolve on return type. As a matter of fact, resolving on
>return type would be much simpler than the comparable parameter resolution.
Well, I actually think I would prefer a less fine grained version, but
as I have said before, if you care about the resolution of overloading
then there is something wrong with your design.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 13 Jun 2001 01:13:33 GMT Raw View
In article <sswV6.158121$p33.3307749@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>I have stated repeatedly that I think return type resolution should only be
>invoked when parameter resolution is ambiguous,
Sorry, I missed that. The result of following that line would have so
little utility as to be not worth the time taken discussing it. BTW, did
you mean ambiguity or two functions whose only difference was in their
return type?
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 7 Jun 2001 21:31:21 GMT Raw View
In article <slrn9hv3kg.ik.news/comp.std.c++@ns.nmhq.net>, Niklas
Matthies <news/comp.std.c++@nmhq.net> writes
>No, they don't, they all return "the author". Of course, what "the
>author" is depends on what the caller expects it to be.
>I don't see why this should be less appropriate than
>
> void Document::set_author(const char *);
> void Document::set_author(const string &);
> void Document::set_author(const Author &);
>
>Or do you think this is likewise an abuse of overloading?
Yes. The first two are acceptable in the same context because,
unfortunately, string literals are arrays of const char. However, I
think the third case in the context of the other two indicates a design
flaw.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Thu, 7 Jun 2001 21:32:07 GMT Raw View
Here is a problem with overloading by return type:
First, in C++ it is possible to drop the return value, which could be
viewed as an implicit "void" is added:
A f();
is really
(A|void) f();
Suppose I fix the problem by adding the word "no_void". Then what about
the following code:
class A { ... };
class B { ... };
int operator+(const A&, const A&);
int operator+(const B&, const B&);
no_void A f();
no_void B f(); // Overloading by return type.
int g() {
int n = f() + f();
return n;
}
Here, the problem is f() + f() line: is it the f returning an A or a B?
Somehow this must be explicitly indicated.
But one can also see that the type analysis goes the wrong way, from the
outside of towards the inside of functions, the opposite of how the
functions are evaluated. So one tries to mix to incompatible evaluation
directions here.
There are systems doing such type analysis, like the Hindley-Milner used
in functional languages such as Haskell. But then my hunch is that one
would land on a more advanced template system rather than a "overloading
by return type".
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: markw65@my-deja.com (Mark Williams)
Date: Fri, 8 Jun 2001 19:24:03 GMT Raw View
remove.haberg@matematik.su.se (Hans Aberg) wrote in message news:<remove.haberg-0706012030210001@du135-226.ppp.su-anst.tninet.se>...
> Here is a problem with overloading by return type:
>
> First, in C++ it is possible to drop the return value, which could be
> viewed as an implicit "void" is added:
> A f();
> is really
> (A|void) f();
>
> Suppose I fix the problem by adding the word "no_void". Then what about
> the following code:
> class A { ... };
> class B { ... };
>
> int operator+(const A&, const A&);
> int operator+(const B&, const B&);
>
> no_void A f();
> no_void B f(); // Overloading by return type.
>
> int g() {
> int n = f() + f();
> return n;
> }
>
> Here, the problem is f() + f() line: is it the f returning an A or a B?
> Somehow this must be explicitly indicated.
>
> But one can also see that the type analysis goes the wrong way, from the
> outside of towards the inside of functions, the opposite of how the
> functions are evaluated. So one tries to mix to incompatible evaluation
> directions here.
>
> There are systems doing such type analysis, like the Hindley-Milner used
> in functional languages such as Haskell. But then my hunch is that one
> would land on a more advanced template system rather than a "overloading
> by return type".
And yet C++ already handles this...
class A { ... };
class B { ... };
int operator+(const A&, const A&);
int operator+(const B&, const B&);
class f {
public:
operator A();
operator B();
};
int g() {
int n = f() + f();
return n;
}
Now of course, in this particular case, it fails to compile due to
ambiguity; but remove one of the operator + definitions, and it will
compile.
What problems do you think your example exhibits that are not already
present in the language?
Mark Williams
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Fri, 8 Jun 2001 20:05:20 GMT Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message
news:Imj31TBWF1H7Ewes@ntlworld.com...
> In article <AdBT6.121186$p33.2564425@news1.sttls1.wa.home.com>, Paul
> Mensonides <pmenso57@home.com> writes
> >int* operator new(std::size_t size) {
> > // allocate on "int" heap
> >}
> >
> >double* operator new(std::size_t size) {
> > // allocate on "double" heap
> >}
> >
> >This is somewhat cleaner than the equivalent type-switch:
>
> Now you want to pervert operator new as well! What is wrong with using
> the new expression for this purpose? Why on Earth would any programmer
> want to have distinct heaps for built-in types? Even allowing that they
> did, how could they then use your operators in the context of a new
> expression?
fast free store allocators, memory fragmentation, etc.
> Of course there are answers to those questions, but you are asking that
> everyone else pay in increased complexity and code fragility for a very
> minor gain for your coding style.
No, I'm not. You don't pay for what you don't use. You don't have to use
overloading by return type if you don't want to. And how exactly does this
increase code fragility? Overloading by parameter type is absolutely no
different. The return type is just one more part of a function signature.
Actually, this operator new() example isn't my "coding style." It is merely an
example of what one might do with overloading by return type. Which in the case
of many separately allocated free store built-in types, this is not that
unusual.
> It is seeing examples such as yours that convinces me that we were very
> sensible in disallowing overloading by return type.
>
>
> Francis Glassborow ACCU
> 64 Southfield Rd
> Oxford OX4 1PA +44(0)1865 246490
> All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Fri, 8 Jun 2001 23:23:02 GMT Raw View
In article <9EXT6.127350$p33.2709548@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>No, I'm not. You don't pay for what you don't use. You don't have to use
>overloading by return type if you don't want to.
If the compiler has to support overloading by return type, I pay for it
in increased complexity of the compiler and in its inability to detect
some types of error. These errors are actually much more subtle than the
ones that result from overloading on parameters. It will also require me
to use casts to resolve ambiguities, you maybe happy to litter your code
with casts, I am not.
I think we will just have to differ, but do not complain that the
Standards Committees do not listen, they do but often we think ideas are
wrong, half baked or add unnecessary complexity. If you want your ideas
acted on you have to promote them, you have to do the work and in the
end you have to be there to vote.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Fri, 8 Jun 2001 23:27:58 GMT Raw View
Paul Mensonides wrote:
...
> No, I'm not. You don't pay for what you don't use. You don't have to use
> overloading by return type if you don't want to. And how exactly does this
How can you NOT use it? It's not a feature you can turn on and off. If
you define two functions that differ only in their return type, a
language that allows such overloading would NOT mandate the diagnostic
that you would devoutly hope for, if such overloading was unintentional.
> increase code fragility? Overloading by parameter type is absolutely no
> different. The return type is just one more part of a function signature.
As has been repeatedly pointed out, the return type is NOT part of the
function signature. You may be suggesting that it should be, but your
wording should reflect the fact that it's not currently the case.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: remove.haberg@matematik.su.se (Hans Aberg)
Date: Fri, 8 Jun 2001 23:32:10 GMT Raw View
In article <10f784d5.0106080730.6351ac0a@posting.google.com>,
markw65@my-deja.com (Mark Williams) wrote:
>And yet C++ already handles this...
>
>class A { ... };
>class B { ... };
>
>int operator+(const A&, const A&);
>int operator+(const B&, const B&);
>
>class f {
>public:
> operator A();
> operator B();
>};
>
>int g() {
> int n = f() + f();
> return n;
>}
>
>Now of course, in this particular case, it fails to compile due to
>ambiguity; but remove one of the operator + definitions, and it will
>compile.
The original C types have circular type conversions, and one can create
such circular type conversions in C++ using A::operator B() type
conversion.
But most seems to agree that one would have been better off without the
original C circular type conversions, and that one should avoid using them
in C++ programming as much as possible. -- A::operator B() are only there
to handle cases where there are no better solutions. The rule is, if you
can avoid A::operator B() type conversions, don't use them.
>What problems do you think your example exhibits that are not already
>present in the language?
So what you propose is evidently to make worse the problems that people
want to alleviate; I mean, if you really mean that it is OK to add just
any amount of ambiguities that makes real life C++ programming more
difficult.
But I think the real problem one will hit when trying to implement
overloading by return type is that one has to make the type inference from
the other end, from the returns towards the arguments, and combine that
with the already present type inference, which goes from the arguments
towards the returns.
What kind of type inference system do you propose, that is, what does the
theory look like, and how is it implemented in a compiler?
Right now, I have seen a lot of posts of the kind that this idea would be
great, but nothing more tangible.
Hans Aberg * Anti-spam: remove "remove." from email address.
* Email: Hans Aberg <remove.haberg@member.ams.org>
* Home Page: <http://www.matematik.su.se/~haberg/>
* AMS member listing: <http://www.ams.org/cml/>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Sun, 10 Jun 2001 11:19:23 GMT Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message
news:Y2mzhiA9JVI7EwlO@ntlworld.com...
> In article <9EXT6.127350$p33.2709548@news1.sttls1.wa.home.com>, Paul
> Mensonides <pmenso57@home.com> writes
> >No, I'm not. You don't pay for what you don't use. You don't have to use
> >overloading by return type if you don't want to.
>
> If the compiler has to support overloading by return type, I pay for it
> in increased complexity of the compiler and in its inability to detect
> some types of error. These errors are actually much more subtle than the
> ones that result from overloading on parameters. It will also require me
> to use casts to resolve ambiguities, you maybe happy to litter your code
> with casts, I am not.
Insignificant increased complexity, nor does this preclude diagnostic warnings.
Give me an example of an error that is "more subtle" than the ones that result
from overloading parameters. You already have to use casts to resolve
ambiguities on parameters. How is that much different? You would only have to
"litter your code" with casts if you routinely rely on various forms of implicit
conversion which is bad style anyway.
> I think we will just have to differ, but do not complain that the
> Standards Committees do not listen, they do but often we think ideas are
> wrong, half baked or add unnecessary complexity. If you want your ideas
> acted on you have to promote them, you have to do the work and in the
> end you have to be there to vote.
I do not think that the committee does not listen. I think that the committee
tends to over-exaggerate the complexity or "danger" of a given feature. Often,
it then is considered wrong or "half-baked" based entirely on those ideas and a
few toy examples. Granted, this is not always the case. I am not even a huge
proponent of return type overloading. I'm merely pointing out that it is not
significantly different than parameter overloading, and that it would be a nice
feature for the sake of orthogonality and that the required mechanism is already
mostly implemented via sizeof and function pointers.
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Thu, 7 Jun 2001 00:06:11 GMT Raw View
> Saying the standard is inconsistent in that regard doesn't make it so.
> There is no inconsistence resulting from the rules dictated by the
> standard in not including the return type in the function signature.
I didn't mean that the standard is inconsistent with regard to it's own
definition of a function signature. I think the standard is inconsistent
when not considering the return type of the function type when doing the
overloading resolution, just like it would be if it excluded the first
parameter of the function in the function signature. IMO overload resolution
is about determining the type of the function and the return type is part of
the type of the function. In that regard the standard is inconsistent.
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Thu, 7 Jun 2001 01:32:12 GMT Raw View
> I think that these arguments about overloading on return values actually
> show a divergent concept of what overloading is for. IMO overloading is
> about compile time polymorphism. I.e. you want to do conceptually the
> same thing, but the implementation depends on the context. Now to me a
> function does, conceptually, two things; it evaluates a return value and
> has side effects.
I agree on that but I'd like to point out that the return type is also part
of the context.
> If all you change is the type of the return value then the evaluation is
> for a different thing and so should have a different name.
In most of the cases this is indeed true, still I think it's a dangerous
generalization of the standard to impose a restriction that says it always
is that way. IMO it's counter-intuitive with regard to the flexibility
aspect of C++.
> The entire thrust of C++ overloading is in this direction, overloading
> is scope dependant (i.e. it takes place in a tightly defined context) I
> have yet to see a convincing argument for extending overloading to
> return values, indeed I think overloaded functions that have different
> return types should always be examined very carefully, sometimes it will
> make sense, but often it just highlights a design flaw.
Here's one example. When dealing with templates, consistency is important.
Let's assume one want to create an object in a function template. The object
is created by a function named create. There will exist numerous create
functions that only differ by the return type. As it is now one have to wrap
the create functions in classes. What I object against, is to impose a
restriction that can lead to unnecessary and tedious workarounds, without
really buying us anything.
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Thu, 7 Jun 2001 01:39:44 GMT Raw View
On Wed, 6 Jun 2001 14:33:35 GMT, Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> In article <9fjarp$4c1t8$1@ID-47792.news.dfncis.de>, Bo-Staffan Lankinen
> <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> writes
> >I don't think that's a valid argument. It would be perfectly feasible to
> >include the return value in the overload resolution. If the overload
> >resolution, due to the return value, results in an ambiguity, one has to
> >disambiguate it with an explicit cast, just like one has to do when an
> >ambiguity is caused by the arguments.
>
> I think that these arguments about overloading on return values actually
> show a divergent concept of what overloading is for. IMO overloading is
> about compile time polymorphism. I.e. you want to do conceptually the
> same thing, but the implementation depends on the context. Now to me a
> function does, conceptually, two things; it evaluates a return value and
> has side effects.
>
> If all you change is the type of the return value then the evaluation is
> for a different thing and so should have a different name.
I can think of counterexamples, for example
const char * Document::author();
string Document::author();
Person Document::author();
or
int max_prime() { ... compute maximum prime number <= INT_MAX ... }
long max_prime() { ... compute maximum prime number <= LONG_MAX ... }
int i = max_prime();
long l = max_prime();
The functions conceptually do the same thing. While there may be better
ways to implement such functionality, this doesn't mean that compile
time polymorphism could not manifest itself in overloading on return
type.
-- Niklas Matthies
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Thu, 7 Jun 2001 02:22:39 GMT Raw View
"Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> wrote in
message news:9fmgab$4qbs8$1@ID-47792.news.dfncis.de...
> > I think that these arguments about overloading on return values actually
> > show a divergent concept of what overloading is for. IMO overloading is
> > about compile time polymorphism. I.e. you want to do conceptually the
> > same thing, but the implementation depends on the context. Now to me a
> > function does, conceptually, two things; it evaluates a return value and
> > has side effects.
>
> I agree on that but I'd like to point out that the return type is also part
> of the context.
You can already overload with different return types:
void f();
int f(int);
In other words, there is no enforcement by the language to enforce the supposed
semantic similarity. If you don't have overloading by return type, people end
up faking it anyway:
int f(int) { /* unused parameter */ }
double f(double) { /* unused parameter */ }
void g() {
int x = f(x);
double y = f(y);
}
Or you have to be explicit with namespaces:
namespace _int {
int f();
}
namespace _double {
double f();
}
void g() {
int x = _int::f();
double y = _double::f();
}
This type of thing is relatively common, and the workarounds for lack of
overloading the return type are annoying. Overloading operator new based on
return type would be great:
int* operator new(std::size_t size) {
// allocate on "int" heap
}
double* operator new(std::size_t size) {
// allocate on "double" heap
}
This is somewhat cleaner than the equivalent type-switch:
void* operator new(std::size_t size) {
if (size == sizeof(int)) {
// allocate on "int" heap
}
else if (size == sizeof(double)) {
// allocate on "double" heap
}
else {
// allocate on normal heap
}
}
This is just a indirect type switch, and this type of thing should be cleaner.
Likewise using namespaces for this effect is tedious:
namespace _int {
void* operator new(std::size_t size);
}
namespace _double {
void* operator new(std::size_t size);
}
I'm not even sure what syntax to use when calling these functions. VC++ makes
me do this:
int* x = reinterpret_cast<int*>(_int::operator new(sizeof(int)));
double* y = reinterpret_cast<double*>(_double::operator new(sizeof(double)));
?
Paul Mensonides
> > If all you change is the type of the return value then the evaluation is
> > for a different thing and so should have a different name.
>
> In most of the cases this is indeed true, still I think it's a dangerous
> generalization of the standard to impose a restriction that says it always
> is that way. IMO it's counter-intuitive with regard to the flexibility
> aspect of C++.
>
> > The entire thrust of C++ overloading is in this direction, overloading
> > is scope dependant (i.e. it takes place in a tightly defined context) I
> > have yet to see a convincing argument for extending overloading to
> > return values, indeed I think overloaded functions that have different
> > return types should always be examined very carefully, sometimes it will
> > make sense, but often it just highlights a design flaw.
>
> Here's one example. When dealing with templates, consistency is important.
> Let's assume one want to create an object in a function template. The object
> is created by a function named create. There will exist numerous create
> functions that only differ by the return type. As it is now one have to wrap
> the create functions in classes. What I object against, is to impose a
> restriction that can lead to unnecessary and tedious workarounds, without
> really buying us anything.
>
> Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 7 Jun 2001 10:16:34 GMT Raw View
In article <slrn9htdon.3sb.news/comp.std.c++@ns.nmhq.net>, Niklas
Matthies <news/comp.std.c++@nmhq.net> writes
>> If all you change is the type of the return value then the evaluation is
>> for a different thing and so should have a different name.
>
>I can think of counterexamples, for example
>
> const char * Document::author();
> string Document::author();
> Person Document::author();
And I think those are a good example of why we should not overload on
return type. Give the functions different names because they really do
different things (actually, the string version is probably already
provided by the Person version so if I want the string I would writie
something like:
article.author().name();
which, among other things, provides documentation of intent.
>
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 7 Jun 2001 10:24:58 GMT Raw View
In article <9fmgab$4qbs8$1@ID-47792.news.dfncis.de>, Bo-Staffan Lankinen
<bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> writes
>Here's one example. When dealing with templates, consistency is important.
>Let's assume one want to create an object in a function template. The object
>is created by a function named create. There will exist numerous create
>functions that only differ by the return type. As it is now one have to wrap
>the create functions in classes. What I object against, is to impose a
>restriction that can lead to unnecessary and tedious workarounds, without
>really buying us anything.
Not true, and in addition I can hardly visualise a more dangerous
example of using return type for 'overloading' though I do not think
that term should be used for instantiations of function templates.
Explicit instantiation of a function template resolves the issue and
makes it quite clear to all concerned as to exactly what is being
created.
mytype const & mt_ref = create<mytype>();
seems to be far safer in an environment where polymorphism is common.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 7 Jun 2001 10:25:09 GMT Raw View
In article <9fmg95$4lct1$1@ID-47792.news.dfncis.de>, Bo-Staffan Lankinen
<bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> writes
>I didn't mean that the standard is inconsistent with regard to it's own
>definition of a function signature. I think the standard is inconsistent
>when not considering the return type of the function type when doing the
>overloading resolution, just like it would be if it excluded the first
>parameter of the function in the function signature. IMO overload resolution
>is about determining the type of the function and the return type is part of
>the type of the function. In that regard the standard is inconsistent.
That entirely depends on what you believe the purpose of overloading is.
Clearly what is provided by C++ is different from what you want. That
does not make either C++ or you wrong. However it does suggest that you
should try to understand what overloading is for.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Jay Levitt <jaythemailguy@aol.com>
Date: Thu, 7 Jun 2001 16:50:08 GMT Raw View
In article <JbhT6.1185$Lz4.645539@typhoon.san.rr.com>, s.schulman@berlin.de
says...
> double f(double){ }
> int f(int){ }
>
> main(){
> short s = 0;
> double d = foo(s);
> }
>
> Which function should be used?
> f(int) seemed to be the better candidate because of the argument-type, but
> f(double) has the better fitting return type, so which function should be
> used?!
>
How does this differ from...
void f(double, double) { }
void f(int, int) { }
main(){
short s = 0;
double d = 0;
f(d, s);
}
--
Jay Levitt | This is not the start of World War III
Wellesley, MA | No political ploys
jay@jay.fm | I think both your constitutions are
http://www.jay.fm | terrific, so now you know - be good boys.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: news/comp.std.c++@nmhq.net (Niklas Matthies)
Date: Thu, 7 Jun 2001 17:04:57 GMT Raw View
On Thu, 7 Jun 2001 10:16:34 GMT, Francis Glassborow <francis.glassborow@ntlworld.com> wrote:
> In article <slrn9htdon.3sb.news/comp.std.c++@ns.nmhq.net>, Niklas
> Matthies <news/comp.std.c++@nmhq.net> writes
> >> If all you change is the type of the return value then the evaluation is
> >> for a different thing and so should have a different name.
> >
> >I can think of counterexamples, for example
> >
> > const char * Document::author();
> > string Document::author();
> > Person Document::author();
>
> And I think those are a good example of why we should not overload on
> return type. Give the functions different names because they really do
> different things
No, they don't, they all return "the author". Of course, what "the
author" is depends on what the caller expects it to be.
I don't see why this should be less appropriate than
void Document::set_author(const char *);
void Document::set_author(const string &);
void Document::set_author(const Author &);
Or do you think this is likewise an abuse of overloading?
-- Niklas Matthies
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 7 Jun 2001 17:02:57 GMT Raw View
In article <AdBT6.121186$p33.2564425@news1.sttls1.wa.home.com>, Paul
Mensonides <pmenso57@home.com> writes
>int* operator new(std::size_t size) {
> // allocate on "int" heap
>}
>
>double* operator new(std::size_t size) {
> // allocate on "double" heap
>}
>
>This is somewhat cleaner than the equivalent type-switch:
Now you want to pervert operator new as well! What is wrong with using
the new expression for this purpose? Why on Earth would any programmer
want to have distinct heaps for built-in types? Even allowing that they
did, how could they then use your operators in the context of a new
expression?
Of course there are answers to those questions, but you are asking that
everyone else pay in increased complexity and code fragility for a very
minor gain for your coding style.
It is seeing examples such as yours that convinces me that we were very
sensible in disallowing overloading by return type.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Tue, 5 Jun 2001 15:31:09 GMT Raw View
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message >
Samuel Schulman
> <s.schulman@berlin.de> writes
> >Absolutely.
> >
> >e.g. what is not allowed:
> >
> >int* create();
> >double* create();
> >
> >this will not be allowed as the functions differ only by return type, but
> >
> >template<class T>
> >T* create();
> >
> >create<int>();
> >create<double>();
>
> That is NOT overloading the programmer must explicitly select the
> version required as the compiler cannot determine it for itself.
>
Let's see if I got this right.
So the reason this is allowed is because of the explicit specified type.
Whereas for a regular function, which differs only in the return type, a
compiler would be able to instantiate two different functions, he would not
be able(or it would leed to a whole bunch of other problems), without any
help,
to resolve the function call, and because there is no notion of explicitly
specifing
which function we would like to use(if no argument type exists), this is not
allowed.
Correct?
> >
> >will be allowed.
> >
> >Samuel
> >
>
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Pierre Baillargeon <pb@artquest.net>
Date: Tue, 5 Jun 2001 15:36:25 GMT Raw View
Samuel Schulman wrote:
>
> "James Kuyper Jr." wrote in message:
> > Samuel Schulman wrote:
> > >
> > > This is a question which has been on my mind for a while.
> > >
> > > The standards states that a function cannot be overloaded by return type
> > > only(13.1.2), yet there is the possibility to do exactly that by using
> > > templates.
> >
> > Could you demonstrate what you're referring to?
> >
>
> template<class T>
> T* create();
>
> create<int>();
> create<double>();
>
> will be allowed.
There is also the possibility of using the conversion operator on a
proxy:
struct proxy
{
operator int*();
operator double*();
};
proxy create();
Here the compiler will figure out which conversion operator to call, if
any is possible. The downside is that since a conversion operator is
used, and the fact that the language permits a single conversion, you
won't be able to benefit from implicit conversion of the desired result
type if it is needed. Were functions overloadable on return type, you
would not loose that capability.
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Igor Krasnopeev <dark__raven@mail.ru>
Date: Tue, 5 Jun 2001 18:05:57 GMT Raw View
Samuel Schulman wrote:
>> >create<int>();
>> >create<double>();
>>
>> That is NOT overloading the programmer must explicitly select the
>> version required as the compiler cannot determine it for itself.
>>
>
>Let's see if I got this right.
>
>So the reason this is allowed is because of the explicit specified type.
>Whereas for a regular function, which differs only in the return type, a
>compiler would be able to instantiate two different functions, he would not
>be able(or it would leed to a whole bunch of other problems), without any
>help,
>to resolve the function call, and because there is no notion of explicitly
>specifing
>which function we would like to use(if no argument type exists), this is not
>allowed.
>
>Correct?
Yes. For, example:
int* i = create(); //which create?
will not work.
--
Igor Krasnopeev
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Tue, 5 Jun 2001 23:13:33 GMT Raw View
> Yes. For, example:
>
> int* i = create(); //which create?
I don't think that's a valid argument. It would be perfectly feasible to
include the return value in the overload resolution. If the overload
resolution, due to the return value, results in an ambiguity, one has to
disambiguate it with an explicit cast, just like one has to do when an
ambiguity is caused by the arguments. Like,
int* i = static_cast<int*>(create());
IMO the standard is inconsistent when not including the return value in the
overloading resolution, since it's part of the function signature.
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Tue, 5 Jun 2001 23:43:38 GMT Raw View
> int* i = static_cast<int*>(create());
Ops, in the case above an explicit cast shoudn't be needed, since int*
create() is an exact match for int* i=create(). However it should be needed
in,
static_cast<int*>(create()); //should call int* create()
static_cast<double*>(create()); //should call double* create()
float create();
double create();
int i=static_cast<int>(static_cast<double>(create())); //should call
double create()
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Wed, 6 Jun 2001 03:19:32 GMT Raw View
"Bo-Staffan Lankinen" wrote :
> > Yes. For, example:
> >
> > int* i = create(); file://which create?
>
> I don't think that's a valid argument. It would be perfectly feasible to
> include the return value in the overload resolution. If the overload
> resolution, due to the return value, results in an ambiguity, one has to
> disambiguate it with an explicit cast, just like one has to do when an
> ambiguity is caused by the arguments. Like,
>
> int* i = static_cast<int*>(create());
>
> IMO the standard is inconsistent when not including the return value in
the
> overloading resolution, since it's part of the function signature.
>
First I had the same thought, but then.....
double f(double){ }
int f(int){ }
main(){
short s = 0;
double d = foo(s);
}
Which function should be used?
f(int) seemed to be the better candidate because of the argument-type, but
f(double) has the better fitting return type, so which function should be
used?!
Adding the casting syntax, to make it explicitly which function we want to
use, would bring up other questions, which would need to be resolved(from an
implementation perspective),
and adding this functionality appears to me(maybe wrongly) would do more
harm than good.
e.g. extensive use of casting to resolve function calls.
Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: James Dennett <jdennett@acm.org>
Date: Wed, 6 Jun 2001 03:30:33 GMT Raw View
Bo-Staffan Lankinen wrote:
>
> > Yes. For, example:
> >
> > int* i = create(); //which create?
>
> I don't think that's a valid argument. It would be perfectly feasible to
> include the return value in the overload resolution. If the overload
> resolution, due to the return value, results in an ambiguity, one has to
> disambiguate it with an explicit cast, just like one has to do when an
> ambiguity is caused by the arguments. Like,
>
> int* i = static_cast<int*>(create());
>
> IMO the standard is inconsistent when not including the return value in the
> overloading resolution, since it's part of the function signature.
The return value is *not* part of the function signature as
defined by C++.
-- James Dennett
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Igor Krasnopeev <dark__raven@mail.ru>
Date: Mon, 4 Jun 2001 20:05:15 GMT Raw View
Samuel Schulman wrote:
>> Could you demonstrate what you're referring to?
>>
>
>Absolutely.
>
>e.g. what is not allowed:
>
>int* create();
>double* create();
>
>this will not be allowed as the functions differ only by return type, but
>
>template<class T>
>T* create();
>
>create<int>();
>create<double>();
>
>will be allowed.
>
>Samuel
Yes, but
create<int>();
and
create<double>();
is 2 different functions, and there is no overloading problem between them.
--
Igor Krasnopeev
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Mon, 4 Jun 2001 21:31:30 GMT Raw View
In article <JvDS6.26157$Ox.12446975@typhoon.san.rr.com>, Samuel Schulman
<s.schulman@berlin.de> writes
>Absolutely.
>
>e.g. what is not allowed:
>
>int* create();
>double* create();
>
>this will not be allowed as the functions differ only by return type, but
>
>template<class T>
>T* create();
>
>create<int>();
>create<double>();
That is NOT overloading the programmer must explicitly select the
version required as the compiler cannot determine it for itself.
>
>will be allowed.
>
>Samuel
>
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Tue, 5 Jun 2001 14:39:46 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:JvDS6.26157$Ox.12446975@typhoon.san.rr.com...
> "James Kuyper Jr." wrote in message:
> > Samuel Schulman wrote:
> > >
> > > This is a question which has been on my mind for a while.
> > >
> > > The standards states that a function cannot be overloaded by return type
> > > only(13.1.2), yet there is the possibility to do exactly that by using
> > > templates.
> >
> > Could you demonstrate what you're referring to?
> >
>
> Absolutely.
>
> e.g. what is not allowed:
>
> int* create();
> double* create();
>
> this will not be allowed as the functions differ only by return type, but
>
> template<class T>
> T* create();
>
> create<int>();
> create<double>();
>
> will be allowed.
>
> Samuel
The implementation for overloading based on return type is pretty much already
there in sizeof and function pointers. Consider:
typedef void (*pf)();
typedef int (*pf2)(int);
void f();
int f(int);
void g() {
pf a = &f;
pf2 b = &f;
}
Which "f" is already based on the context of the expression on the left (which
sizeof is already required to be able to figure out the type of anyway). That
is not a whole lot different than this:
void f();
int f(int);
int f();
void g() {
int x = f();
}
Of course, you could solve all backward compatibility problems by only invoking
return type resolution when parameter resolution is ambiguous. "no context"
would default to the void return type or be ambiguous:
e.g. if you had to functions:
double f();
int f();
called like this:
void g() {
f(); // ambiguous: no context
}
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Wed, 6 Jun 2001 14:29:44 GMT Raw View
"Paul Mensonides" <pmenso57@home.com> wrote :
> "Samuel Schulman" <s.schulman@berlin.de> wrote :
> > "James Kuyper Jr." wrote in message:
> > > Samuel Schulman wrote:
> > > >
> > > > This is a question which has been on my mind for a while.
> > > >
> > > > The standards states that a function cannot be overloaded by return
type
> > > > only(13.1.2), yet there is the possibility to do exactly that by
using
> > > > templates.
> > >
> > > Could you demonstrate what you're referring to?
> > >
> >
> > Absolutely.
> >
> > e.g. what is not allowed:
> >
> > int* create();
> > double* create();
> >
> > this will not be allowed as the functions differ only by return type,
but
> >
> > template<class T>
> > T* create();
> >
> > create<int>();
> > create<double>();
> >
> > will be allowed.
> >
> > Samuel
>
> The implementation for overloading based on return type is pretty much
already
> there in sizeof and function pointers. Consider:
>
> typedef void (*pf)();
> typedef int (*pf2)(int);
>
> void f();
> int f(int);
>
> void g() {
> pf a = &f;
> pf2 b = &f;
> }
>
> Which "f" is already based on the context of the expression on the left
(which
> sizeof is already required to be able to figure out the type of anyway).
I am not quite sure what you mean, when you refer to the sizeof operator.
And if I am not mistaken nothing equivalently exists what would have to do
with function pointers.
The example shown does not use 'overloading by return type', the function
pointers are assigned to the function which matches the type of the pointer.
>That
> is not a whole lot different than this:
>
> void f();
> int f(int);
> int f();
>
> void g() {
> int x = f();
> }
I actually believe, that this is very different.
> Of course, you could solve all backward compatibility problems by only
invoking
> return type resolution when parameter resolution is ambiguous. "no
context"
> would default to the void return type or be ambiguous:
>
> e.g. if you had to functions:
>
> double f();
> int f();
>
> called like this:
>
> void g() {
> f(); // ambiguous: no context
> }
>
> Paul Mensonides
>
Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Wed, 6 Jun 2001 14:31:47 GMT Raw View
> The return value is *not* part of the function signature as
> defined by C++.
Sorry for expressing myself unclear. That last sentence should be:
IMO the standard is inconsistent when not including the return type in the
overloading resolution. The return type of a function is part of the type of
the function and it should be part of the function signature.
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 6 Jun 2001 14:33:35 GMT Raw View
In article <9fjarp$4c1t8$1@ID-47792.news.dfncis.de>, Bo-Staffan Lankinen
<bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> writes
>I don't think that's a valid argument. It would be perfectly feasible to
>include the return value in the overload resolution. If the overload
>resolution, due to the return value, results in an ambiguity, one has to
>disambiguate it with an explicit cast, just like one has to do when an
>ambiguity is caused by the arguments.
I think that these arguments about overloading on return values actually
show a divergent concept of what overloading is for. IMO overloading is
about compile time polymorphism. I.e. you want to do conceptually the
same thing, but the implementation depends on the context. Now to me a
function does, conceptually, two things; it evaluates a return value and
has side effects.
If all you change is the type of the return value then the evaluation is
for a different thing and so should have a different name.
The entire thrust of C++ overloading is in this direction, overloading
is scope dependant (i.e. it takes place in a tightly defined context) I
have yet to see a convincing argument for extending overloading to
return values, indeed I think overloaded functions that have different
return types should always be examined very carefully, sometimes it will
make sense, but often it just highlights a design flaw.
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
Date: Wed, 6 Jun 2001 18:15:28 GMT Raw View
"Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com> writes:
| > The return value is *not* part of the function signature as
| > defined by C++.
|
| Sorry for expressing myself unclear. That last sentence should be:
|
| IMO the standard is inconsistent when not including the return type in the
| overloading resolution.
Saying the standard is inconsistent in that regard doesn't make it so.
There is no inconsistence resulting from the rules dictated by the
standard in not including the return type in the function signature.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Bo-Staffan Lankinen" <bSoP_AsMteSfUfCaKnS_lankinen@hotmail.com>
Date: Wed, 6 Jun 2001 20:16:30 GMT Raw View
> double f(double){ }
> int f(int){ }
>
> main(){
> short s = 0;
> double d = foo(s);
> }
In that case there is no best viable function, just like,
void f(double,double){ }
void f(int,int){ }
int main(){
short s = 0;
double d = 0;
f(d,s);
}
has to be explicitly disambiguated by a cast.
Bo-Staffan
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Paul Mensonides" <pmenso57@home.com>
Date: Wed, 6 Jun 2001 20:45:08 GMT Raw View
"Samuel Schulman" <s.schulman@berlin.de> wrote in message
news:qchT6.1186$Lz4.645683@typhoon.san.rr.com...
> "Paul Mensonides" <pmenso57@home.com> wrote :
> > The implementation for overloading based on return type is pretty much
> already
> > there in sizeof and function pointers. Consider:
> >
> > typedef void (*pf)();
> > typedef int (*pf2)(int);
> >
> > void f();
> > int f(int);
> >
> > void g() {
> > pf a = &f;
> > pf2 b = &f;
> > }
> >
> > Which "f" is already based on the context of the expression on the left
> (which
> > sizeof is already required to be able to figure out the type of anyway).
>
> I am not quite sure what you mean, when you refer to the sizeof operator.
> And if I am not mistaken nothing equivalently exists what would have to do
> with function pointers.
> The example shown does not use 'overloading by return type', the function
> pointers are assigned to the function which matches the type of the pointer.
sizeof() must evaluate (at compile time) the "type" of an expression in order to
determine its size. The mechanism behind sizeof() can figure out the context
for overloading based on return type. In the example above, C++ already
requires a decision between which "f" based on the context of expression in
which it is involved. That decision is really no different than overloading
based on return type. Of course, the example doesn't use overloading based on
return type. I'm just saying that C++ already requires a contextual analysis
and the mechanisms to support overloading based on return type are already
there--just not implemented for this specifically.
> >That
> > is not a whole lot different than this:
> >
> > void f();
> > int f(int);
> > int f();
> >
> > void g() {
> > int x = f();
> > }
>
> I actually believe, that this is very different.
How so? Obviously, one is function pointer assignment, and the other is a
function call. But I'm not talking about the semantics of the example. I'm
talking about the deduction necessary to discover "which f()."
Paul Mensonides
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Sun, 3 Jun 2001 20:34:29 CST Raw View
This is a question which has been on my mind for a while.
The standards states that a function cannot be overloaded by return type
only(13.1.2), yet there is the possibility to do exactly that by using
templates.
How come this is allowed?
(Why it technically happens I believe I understand!)
Samuel Schulman
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: Mon, 4 Jun 2001 03:30:48 GMT Raw View
Samuel Schulman wrote:
>
> This is a question which has been on my mind for a while.
>
> The standards states that a function cannot be overloaded by return type
> only(13.1.2), yet there is the possibility to do exactly that by using
> templates.
Could you demonstrate what you're referring to?
---
[ 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.research.att.com/~austern/csc/faq.html ]
Author: "Samuel Schulman" <s.schulman@berlin.de>
Date: Mon, 4 Jun 2001 17:26:16 GMT Raw View
"James Kuyper Jr." wrote in message:
> Samuel Schulman wrote:
> >
> > This is a question which has been on my mind for a while.
> >
> > The standards states that a function cannot be overloaded by return type
> > only(13.1.2), yet there is the possibility to do exactly that by using
> > templates.
>
> Could you demonstrate what you're referring to?
>
Absolutely.
e.g. what is not allowed:
int* create();
double* create();
this will not be allowed as the functions differ only by return type, but
template<class T>
T* create();
create<int>();
create<double>();
will be allowed.
Samuel
---
[ 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.research.att.com/~austern/csc/faq.html ]