C++ Function Template With Flexible Return Type

22,956

Solution 1

C++0x will allow you to use the auto keyword in order to let the compiler derive the return time of an expression.


For C++03 the only way I found to automatize such process is to define a template class Promotion that defines the strongest type between two types, and then specialize it for any couple of types you might need to use.

template<> class Promotion< long, int > { typedef long strongest; }
template<> class Promotion< int, long > { typedef long strongest; }

and thus:

template< typename T1, typename T2 >
Promotion<T1,T2>::strongest function( const T1 &a, const T2 &b ) { ... }

If you choose to try this solution, I'd suggest to generate the Promotion specializations with an automatically generated header file.


Edit: I reread the question after reading the other (now deleted) answer:

You can't return the type of the smaller variable. That's because the value of the variables will only be found out at runtime, while your function return type must be defined at compile time.

The solution I proposed will return always the strongest type between the two variables' type.

Solution 2

As has been said, you want to take the type that is more generic. Like, int and double should become double; char* and string should become string. This works with my promote<> template. Just write

template <class T1, class T2>
typename promote<T1, T2>::type getMin(T1 const& a, T2 const& b) {
  if(a < b)
    return a;
  return b;
}

This will always return a copy, even if T1 and T2 is the same type (like string), which is why I would overload it for non-const same-type arguments

template <class T>
T &getMin(T &a, T &b) {
  if(a < b)
    return a;
  return b;
}

These two variants seem to be a reasonable configuration. If you want to have a slightly more risky, but in more cases performant, solution, you can accept T const&, also accepting temporaries. If you then use it like getMin(a + b, b + c), which could pass temporaries, and use the result directly, that's all fine. The result is usable and can still be copied into a local variable.

Share:
22,956
Ignatius Reza
Author by

Ignatius Reza

Updated on September 17, 2020

Comments

  • Ignatius Reza
    Ignatius Reza over 3 years

    Let's say that we have a function like so

    template <class T, class T2>
    T getMin(T a, T2 b) {
      if(a < b)
        return a;
      return b;
    }
    

    if we call the function like so

    int a, b;
    long c;
    
    a = getMin(b, c);
    

    if c is < a, then the value of c will be type casted to int.

    Is it possible to make the return type flexible so that it would return an int, or long, or any other type considered smaller by "<" without being type casted?

    edit : the type involved in the function can be anything from simple type to complex classes where typecasting sometime won't be possible.

  • Ben Voigt
    Ben Voigt over 13 years
    No, but decltype makes finding the stronger type really easy. For example, getMin(T a, T2 b) -> decltype(a | b). Then manually writing zillions of specializations is not necessary.
  • peoro
    peoro over 13 years
    Indeed, but auto + decltype are not C++03 standard.
  • Konrad Rudolph
    Konrad Rudolph over 13 years
    Does this compile anywhere? After all, Andrei complained that no current compiler accepted the solution – but admittedly that was several years ago.
  • Johannes Schaub - litb
    Johannes Schaub - litb over 13 years
    @Konrad dunno what his solution was. But from what I remember, he tried to catch more cases with the "getMin" lvalue-returning version.
  • Konrad Rudolph
    Konrad Rudolph over 13 years
    I mean this seminal work: drdobbs.com/184403774 … and I just realized that it’s from 2001 so the relevant paragraph (“there's a little detail worth mentioning. Sadly, Min doesn't work with any compiler I have access to. In fairness, each compiler chokes on a different piece of code.”) is probably obsolete.
  • Ignatius Reza
    Ignatius Reza over 13 years
    This could work, but only when the type involved in the equation is simple type. by returning the strongest type between both, we avoid losing precision, but we still don't get the actual type.
  • peoro
    peoro over 13 years
    As I added with the Edit, a function cannot return a runtime-chosen type. The function must have its return type statically defined at compile time. If it's mandatory for you to get the actual type you can't use a function, a macro would do it, instead. Another solution could be that of returning two values, a T and a T2 object (eg: in a tuple) plus another value to specify which is the right one.