-2

Could you explain me how these functions work?

double f(int i)
{
    cout<<"a";
    return 1;
}

int f(double i)
{
    cout<<"b";
    return 1;
}

For:

f(f(f(1)));

In my opinion the result should be: aaa but it isaba

And same situation with f(f(f(1.1))); I think there should be aab but there is bab

Andreas
  • 5,393
  • 9
  • 44
  • 53
Finer
  • 95
  • 5
  • 3
    _In my opinion the result should be: aaa.._ Why? – B001ᛦ Jan 24 '18 at 11:23
  • 1
    What, exactly is unclear about it? Why do you think it should be `aaa`? – Algirdas Preidžius Jan 24 '18 at 11:23
  • f(1)=1, f(f(1))=1 f(f(f(1)))=1. – Finer Jan 24 '18 at 11:26
  • 3
    @Finer `f(1) = 1.0` – UKMonkey Jan 24 '18 at 11:27
  • `1` is an `int`. `1.0` is a `double`. They appear as and represent the same thing, but are treated differently – Fureeish Jan 24 '18 at 11:27
  • @Fureeish "appear as" they're different sizes, with different formats, I wouldn't say that appear as each other at all. – UKMonkey Jan 24 '18 at 11:35
  • The propertity of size determinates what they are, not how they appear. They represent *and appear* as a value **1**. When we distinguish `1.0` and `1` we are talking about the properties. I get what you are saying though - they are different things, but the fact that they can be mistakenly treated as the same one is a interpretation of *false appearance*. – Fureeish Jan 24 '18 at 11:41
  • 1
    @Finer "_f(1)=1, f(f(1))=1 f(f(f(1)))=1_" Value doesn't matter. All that matters, in overload resolution, is the type. Consider learning from a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Algirdas Preidžius Jan 24 '18 at 11:47
  • But they don't appear as each other at all! Debuggers won't print "1" when you inspect them. If you're thinking about how cout handles them then you can add `<< "1"` and `<< '1'` to the list; but they certainly don't appear to be an int of value 1 either! – UKMonkey Jan 24 '18 at 11:57

3 Answers3

15

When you return from a function, the type of the return value is determined from the function prototype, not what it's written as-is. If the type doesn't match, it'll be implicitly converted to the correct type. So this example function:

double foo(void) { return 1; }

Actually returns double(1), or equivalently, 1.0. It does not return an int because 1 is int. It does, however, convert your int to a double value to match the function's return value type as declared.

So coming to your question, the innermost function called is double f(int), and the second function called is int f(double), and the outermost function called is double f(int). This matched the output you see: aba.

f( f( f(1) ) );
↑  ↑  ↑
|  |  calls double f(int)
|  calls int f(double)
calls double f(int)
iBug
  • 35,554
  • 7
  • 89
  • 134
5

The way the compiler reads your f(f(f(1))); function is from the inside out. Let me elaborate, the compiler sees f(1); and it looks for a function called f that takes an int as an argument so that would be:

 double f(int i)
{
    cout<<"a";
    return 1;
}

Now, once your function executes, it returns a double, hence the second f takes in a double -> which calls your next function that takes double

int f(double i)
{
    cout<<"b";
    return 1;
}

Following the logic explained above, we have arrived at the last/outer layer of your triple f question. Now the compiler has an int and is looking for a function called f that takes int -> which is your first declared function.

And that is why you get aba as a result.

1

prior to your first use of std::cout in your code, add the line

std::cout << std::fixed;

This changes the output (of parameter i) quite a bit by causing int and double to show their 'true colors'. Perhaps this will illustrates what is happening.

Example:

double f(int i)
   {
      std::cout << "  a" << std::setw(9) << i << "    " << std::flush;
      return 1;
   }

int f(double i)
   {
      std::cout << "  b" << std::setw(9) << i << "    " << std::flush;
      return 1;
   }

int main(int , char** )
{
   std::cout << std::fixed << "\n";

   f(f(f(1)));

   std::cout << std::endl;

   f(f(f(1.0)));

   return 0;
}

Generates output:

 a        1      b 1.000000      a        1    
 b 1.000000      a        1      b 1.000000   

The returned value (always integer 1) is implicitly transformed to the return type, which is different for the two functions.

Which function is invoked is determined by the signature of the function, i.e. the parameters actual type. This also illustrates that the return type is not part of the signature.

2785528
  • 5,438
  • 2
  • 18
  • 20