4

I made a template and an auto function that compare 2 values and return the smallest one. This is my code:

#include <iostream>
using namespace std;

// Template with a value returning function: PrintSmaller
template <typename T, typename U>
auto PrintSmaller(T NumOne, U NumTwo) {
    if (NumOne > NumTwo) {
        return NumTwo;
    }
    else {
        return NumOne;
    }
}

int main() {

    int iA = 345;
    float fB = 23.4243;

    cout << PrintSmaller(iA, fB) << endl;
    cout << PrintSmaller(fB, iA) << endl;

    return 0;
}

But it won't compile, I get this error on VS 2015: Error C3487 'int': all return expressions must deduce to the same type: previously it was 'float'

However, if I delete the if statement and write the function PrintSmaller like this it works with no problems :

auto PrintSmaller(T NumOne, U NumTwo) {
return (NumOne < NumTwo ? NumOne : NumTwo);
}

What is the difference ? and why the first code won't compile ? Thank you.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
Mike .H
  • 43
  • 4
  • 1
    The ternary statement is probably inducing an implicit conversion. [This](http://stackoverflow.com/a/8535301/1460794) might be related. – wally Jan 08 '17 at 18:45
  • Are you compiling with -std=c++11 or -std=c++14 ? – JVApen Jan 08 '17 at 18:56

3 Answers3

9

A function can only have a single return type. Using return type deduction means that it will be deduced based on the type of the expression in the first return statement the parser sees. If later return statements do not return expressions of the same type, then the function is considered to be self-contradictory and thus ill-formed.

In the second case, the ?: determines the type of the expression based on a common type determined based on the second and third sub-expressions. The two sub-expressions will be converted to this common type.

That's different from how return type deduction works. If you intend for your first case to work, then you need to explicitly convert the returned value to the desired return type.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
0

As you have asked this question with the c++11 marker, I suppose you are using C++11. Unfortunately, the C++11 standard states that auto-type deduction (also for lambdas) is limited to a single statement.

As the ?: operator is an expression instead of a statement, this will work while the if-else is a statement and doesn't meet the requirements.

If you would compile this code with the C++14 standard, you will see that it should compile both cases as this limitation was removed.

JVApen
  • 11,008
  • 5
  • 31
  • 67
0

Until yesterday (2017-12-06) this was not compiling under MSVC. But after VS 15.5 update it does.

    auto msvc_does_compile = [](auto _string)
     {
      using string_type = decltype(_string);
      return std::vector<string_type>{};
     };
   /*
    OK since VS 2017 15.5 update
   auto vec1 = msvc_does_compile( std::string{} );
   */

Adding explicit return type will choke MSVC , but not gcc/clang as usual:

auto msvc_does_not_compile = [](auto _string)
    // explicit return type makes msvc not to compile
    -> std::vector< decltype(_string) >
  {
    using string_type = decltype(_string);
    return std::vector<string_type>{};
  };

And something of the same but simpler will be stopped even at the IDE stage:

    auto msvc_ide_does_not_allow = []( bool wide )
    {
       if (wide)
        return std::vector<std::string>();

        return std::vector<std::wstring>();
    };

Yes, again that troublesome pair gcc/clang has no problems with the above. Try which ever online ide you prefer to convince yourself...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459