8
#include <iostream>

int main(){
    int a = 1;
    long long b = 2;
    std::cout<<(a<b);
    std::cout<<std::min(a, b);
    return 0;
}

> In file included from /usr/include/c++/4.8/bits/char_traits.h:39:0,
>                  from /usr/include/c++/4.8/ios:40,
>                  from /usr/include/c++/4.8/ostream:38,
>                  from /usr/include/c++/4.8/iostream:39,
>                  from sum_to.cpp:1: /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template<class
> _Tp, class _Compare> const _Tp& std::min(const _Tp&, const _Tp&, _Compare)
>      min(const _Tp& __a, const _Tp& __b, _Compare __comp)
>      ^ /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note:   template argument deduction/substitution failed: sum_to.cpp:7:29:
> note:   deduced conflicting types for parameter ‘const _Tp’ (‘int’ and
> ‘long long int’)
>      std::cout<<std::min(a, b);

---

Thanks to chris comment in function overloading post Template argument deduction doesn't take conversions into account. One template parameter can't match two types

So std::min fail.

Why < would work?

Community
  • 1
  • 1
Kamel
  • 1,856
  • 1
  • 15
  • 25

5 Answers5

7

Because built-in < applies Numeric promotions, and template argument deduction doesn't.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 1
    Could you please give reference specific to `<`? I understood `promotions` but cant find out why `<` is suitable for this `promotions`. – Kamel Aug 11 '15 at 08:23
  • 1
    @Kamel It's the case for all built-in arithmetic operators ([link](http://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversions)). – Quentin Aug 11 '15 at 08:26
  • I read Java's document to learn how to use its SDK, while reading C++'s document to learn how its compiler hacks to run the code. – Kamel Aug 11 '15 at 08:29
  • @Kamel If you mean that C++ is patchy, its not. It's just far more complex than Java, and you need to know more of its pieces to see that they indeed fit together. – Quentin Aug 11 '15 at 08:31
  • Legacy from C. Call it the curse of backwards compatibility with code going back 3 decades. – MSalters Aug 11 '15 at 11:25
3

As explained in other answers, the reason is that std::min requires the types of the arguments to be identical if deduction is to be performed, while < implies the usual arithmetic conversions (§5.9/2), which will make sure that the types are converted to a "common denominator". Note how §13.6/12 lists up built-in operators as candidates:

For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form

// […]
LR operator<(L , R );
// […]

where LR is the result of the usual arithmetic conversions between types L and R.


Actually, std::min should be able to deal with distinct types. The following is a more modern approach:

template <typename T>
constexpr decltype(auto) min(T&& t) {return std::forward<T>(t);}

template <typename T, typename U, typename... Args>
constexpr auto min(T&& t, U&&u, Args&&... args) {
    std::common_type_t<T, U> const& _t(std::forward<T>(t)), _u(std::forward<U>(u));
    return min(_t<_u? _t : _u, std::forward<Args>(args)...);
}

Demo.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Isn't `t` (for primitive types)? Well, it won't make a copy in some cases like your above code will do: that, however, can be fixed with a bit more effort. – Yakk - Adam Nevraumont Aug 11 '15 at 13:21
  • @Yakk I tried something else. However, there might be an `operator<` that compares distinct class types. Then, `a – Columbo Aug 11 '15 at 14:05
  • If we don't enforce order of `<` (reasonable), and our `min` returns a reference (where possible), then `min(a,b,c...)` being `auto&& x = min(forward(b),forward(c)...); return no_rvalue( a – Yakk - Adam Nevraumont Aug 11 '15 at 14:28
2

It is because std::min is a template function.

template <class T> const T& min (const T& a, const T& b) {
  return !(b<a)?a:b;     // or: return !comp(b,a)?a:b; for version (2)
}

so it needs the arguments to have the same type, but if you use (a<b), so a could implicitly converted to a long long

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
Maximilian Ast
  • 3,369
  • 12
  • 36
  • 47
-1

Primitive types don't overload operators, so usual arithmetic conversions are applied and your int is converted to a long long, and the "<" has a valid meaning.

You can't even overload operators for primitive types: https://isocpp.org/wiki/faq/intrinsic-types#intrinsics-and-operator-overloading

Example to show that your int is promoted to long long

// common_type example
#include <iostream>
#include <type_traits>

int main() {

  typedef std::common_type<int, long long>::type A;           // i
  std::cout << "A: " << std::is_same<long long,A>::value << std::endl;

  return 0;
}

Documentation http://en.cppreference.com/w/cpp/language/operator_arithmetic

For the binary operators (except shifts), if the promoted operands have different types, additional set of implicit conversions is applied, known as usual arithmetic conversions with the goal to produce the common type (also accessible via the std::common_type type trait)

dau_sama
  • 4,247
  • 2
  • 23
  • 30
  • Every pair of promoted arithmetic types has operators defined for that pair. `int` is a promoted arithmetic type already. Promotion does not produce anything with a rank greater than `int` unless it doesn't change the type. `int` -> `long long` is not a valid promotion. – chris Aug 11 '15 at 15:31
  • please check my updated answer, I am afraid your comment does not reflect what in reality is happening. "promoted" may have not been the right term, but "usual arithmetic conversions" are applied. – dau_sama Aug 11 '15 at 16:16
-1

The < operator is binary, so the compiler could convert arguments to the same type and compare them.

Otherwise min function should return something. How could compiler guess which type should he return?

Heavy
  • 1,861
  • 14
  • 25