-3
void print( int & a ){ cout << a << endl; }
void print( const int & a ){ cout << 2*a << endl; }
void print( float a ){ cout << 3*a << endl; }

Why is 2 the output of print(1)?

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
  • 2
    Is 1 constant or not? – doctorlove Jan 23 '18 at 13:47
  • 3
    Read about [overload resolution](http://en.cppreference.com/w/cpp/language/overload_resolution). – Arnav Borborah Jan 23 '18 at 13:47
  • @doctorlove it is a constant in all countries using the _système international_, but US defines it in strange units. – YSC Jan 23 '18 at 13:49
  • 3
    The first overload is not viable - an rvalue cannot bind to a non-const lvalue reference. – Igor Tandetnik Jan 23 '18 at 13:50
  • @IgorTandetnik: Bill Gates' compiler allowed it at least up to 2008. – Bathsheba Jan 23 '18 at 13:51
  • @Bathsheba VS6 used to reject 2 for loops with `for (int i` at the start because the variables clashed ... somehow MS and standards don't fit in the same sentence unless it includes "have their own" ... – UKMonkey Jan 23 '18 at 13:57
  • 2
    @Asad Masroor Add one more overloaded function void print( int &&a ) { std::cout << 4 * a << std::endl; } and it will be called.:) – Vlad from Moscow Jan 23 '18 at 14:10
  • @VladfromMoscow: Why not answer, and put this at the end? I'd upvote it. (It being more useful to future readers than my answer.) – Bathsheba Jan 23 '18 at 14:12
  • @Bathsheba You may add this to your answer.:) – Vlad from Moscow Jan 23 '18 at 14:12
  • @VladfromMoscow: But that would require me knowing the precise reason. I'm a charlatan you know ;-) – Bathsheba Jan 23 '18 at 14:13
  • 1
    @UKMonkey - VC6 actually implemented the *proposed* standard for loop variables. The rules were then modified before the standard was published, a few months after the compiler release. Could explain why MS has been reluctant to implement new proposals since? – Bo Persson Jan 23 '18 at 14:20
  • @BoPersson interesting; but didn't really explain why they didn't release an update... I wonder how many times they've released a proposal and then gone with a slightly different version. – UKMonkey Jan 23 '18 at 14:23
  • @UKMonkey - Yes, it was made worse by them taking 5 years to return to C++ after pushing Visual Studio.NET instead. – Bo Persson Jan 23 '18 at 14:30

2 Answers2

7

The tenet of this question is that you need to know that anonymous temporaries cannot bind to non-const references, and they can bind to const references.

1 is an anonymous temporary of type int.

Hence the const int& binding is favoured by overload resolution.

Some compilers (older MSVC) would allow, in error, a binding to int&. In standard C++, if the const int& overload is missing, then the float overload will be called.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

For all three overloads:

  1. (void print( int & a ){ cout << a << endl; }) The first overload is not called, since it only accepts a variable. (Unless you have an old MSVC compiler).
  2. (void print( const int & a )) The second overload is of type const int&, which can accept either a temporary of type int, or a variable of type int.
  3. (void print( float a )) The third overload has an argument of type float, which would work be called if there was no overload of type int.

Thus, since there is an overload that accepts a temporary variable of type int, the second overload is chosen over the third.

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88