Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement a generic min?

Tags:

c++

templates

When I write

T min(T& a,T& b)
{return a<b?a:b;}

and call min(3,4), it will yield a error.

How can I implement a generic min?

like image 318
Ryan_Liu Avatar asked Dec 12 '22 15:12

Ryan_Liu


1 Answers

That's because non-const lvalue references (T&) cannot bind to rvalues (3 and 4 are rvalues, which intuitively means that they do not have an object identity).

Try using lvalue references to const instead, which can bind to rvalues (after all, the min() function is not supposed to alter the state of its arguments).

Besides, do not forget the template<typename T> part if you are writing a function template:

template<typename T> // <== Don't forget this, if you are writing a template
T min(T const& a, T const& b)
//      ^^^^^       ^^^^^
{
    return (a < b) ? a : b;
}

For instance, consider this small program:

#include <iostream>

template<typename T> // <== Don't forget this, if you are writing a template
T min(T const& a, T const& b)
//      ^^^^^       ^^^^^
{
    return (a < b) ? a : b;
}

int main()
{
    int x = 42;
    int y = 1729;

    std::cout << min(x, y) << std::endl; // Passing lvalues, that would be OK also
                                         // with your original code.

    std::cout << min(42, 1729) << std::endl; // Passing rvalues, this would not be OK
                                             // with your original code (non-const
                                             // lvalue references cannot bind to rvalues)
}

Here is a live example.


UPDATE:

The above solution only allows passing values of the same type to min(), otherwise the compiler won't be able to perform type deduction (if the first and second argument have different types, what should T be?):

min(3.14, 42); // Huh? What is `T` here, `double` or `int`?

To force the compiler to use a specific type for T, you can specify the template argument explicitly:

min<double>(3.14, 42);

However, this is not a very elegant choice (the user has to type the correct template argument manually every time). Rather, you could let your function template accept two template type parameters instead of one:

#include <type_traits>

template<typename T, typename U>
typename std::common_type<T, U>::type min(T const& a, U const& b)
{
    return (a < b) ? a : b;
}

And use the std::common_type<> type trait (available since C++11) to figure out the right type to be used as the return type.

Once again, here is a live example.

like image 147
Andy Prowl Avatar answered Dec 27 '22 22:12

Andy Prowl