0

The return type is not part of the symbol name. That makes overloading of a function based on the return type impossible. What is the idea behind this approach?

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
dgrat
  • 2,214
  • 4
  • 24
  • 46

5 Answers5

3

The reason given by Bjarne Stroustrup as part of a post in newsgroup comp.lang.c++, dated 12 January 1998 is

The reason that C++ doesn't allow overload resolution based on a return type (so that you need to use explicit qualification in the examples below) is that I wanted overload resolution to be bottom up. For example, you can determine the meaning of a subexpression a+b without considering the complete expression that a+b is part of. Overload resolution can be subtle so even though I knew how to use return types as part of resolution (Ada showed how), I decided not to. As a result of this decision, a+b means the same in a+b+c as in a+b+d.

Agree with it or not, this is the rationale behind the design decision.

Peter
  • 35,646
  • 4
  • 32
  • 74
1

You can call a function or method and discard it's return value. How should the compiler figure out what function or method should be called then?

int sum(int a, int b)
long sum(int a, int b)

sum(10, 20) // which one should be called?
Patrick Bucher
  • 1,302
  • 2
  • 14
  • 36
1

There's a chicken and egg. Return type isn't considered in overloading rules so isn't part of the function signature.

Although it would appear easy to consider return type in the signature the rules would inevitably become at best complex at worst ambiguous.

Consider relatively harmless looking code like:

foo(bar(x),bim(bam(y)));
Persixty
  • 8,165
  • 2
  • 13
  • 35
0

There's a very easy solution to this problem: templates:

template <typename T>
T sum(double a, double b)
{
    return static_cast<T>(a+b);
}

You call this with sum<int>(5,6), and it'll cast the result to int. This is a bad example, but sometimes this is useful, like the opposite of the famous std::to_string, which is called from_string (it's not part of the standard), but the return value is of your choice using the template.

You can even have fancier ways to specialize the implementation depending on the type using type_traits. In C++11, you can do this:

template <typename T>
T sum(double a, double b)
{
    if(std::is_same<double,T>::value) //if the type is double
        return a+b;
    else
        return static_cast<T>(a+b);
}

Though you have to cast for every case. To make this fancier (and solve the casting problem, which you'll probably understand only if you start involving strings and other classes with scalar types), in C++17, you can use constexpr if and eliminate that problem:

template <typename T>
T sum(double a, double b)
{
    if constexpr(std::is_same<double,T>::value) //if the type is double
        return a+b;
    else
        return static_cast<T>(a+b);
}

In the last branch, the other branch will not make a difference because it'll be evaluated at compile-time. So no casting problems.

The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
0

The others are right that introducing this now would create a lot more problems than it would solve.

It's this way at the moment because it makes logical sense: you say what function (by name) you're going to call, and what arguments you're going to give it; the function is responsible for telling you what you can expect to get back.

Furthermore, being able to call foo(1, 2) one way, then foo(1, 2) in another way, and get two completely different kinds of results back, would be extraordinarily confusing. It's just… wrong!

We identify a function by what we'll provide to it, not by what it'll provide to us.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055