fork(2) download
  1. #include <iostream>
  2. #include <utility>
  3. #include <type_traits>
  4.  
  5. namespace my_min {
  6.  
  7. // a common_type that when fed lvalue references all of the same type, returns an lvalue reference all of the same type
  8. // however, it is smart enough to also understand common_type specializations. This works around a quirk
  9. // in the standard, where (true?x:y) is an lvalue reference, while common_type< X, Y >::type is not.
  10. template<typename... Ts>
  11. struct my_common_type;
  12.  
  13. template<typename T>
  14. struct my_common_type<T>{typedef T type;};
  15.  
  16. template<typename T0, typename T1, typename... Ts>
  17. struct my_common_type<T0, T1, Ts...> {
  18. typedef typename std::common_type<T0, T1>::type std_type;
  19. // if the types are the same, don't change them, unlike what common_type does:
  20. typedef typename std::conditional< std::is_same< T0, T1 >::value,
  21. T0,
  22. std_type >::type working_type;
  23. // Careful! We do NOT want to return an rvalue reference. Just return T:
  24. typedef typename std::conditional<
  25. std::is_rvalue_reference< working_type >::value,
  26. typename std::decay< working_type >::type,
  27. working_type
  28. >::type common_type_for_first_two;
  29. // TODO: what about Base& and Derived&? Returning a Base& might be the right thing to do.
  30. typedef typename my_common_type< common_type_for_first_two, Ts... >::type type;
  31. };
  32. template<typename... Ts>
  33. using my_common_type_t = typename my_common_type<Ts...>::type;
  34.  
  35. template<typename Picker, typename T>
  36. T picked_min(Picker&& /*unused*/, T&&t)
  37. {
  38. return std::forward<T>(t);
  39. }
  40. // slight optimization would be to make Picker be forward-called at the actual 2-arg case, but I don't care:
  41. template<typename Picker, typename T0, typename T1, typename... Ts>
  42. my_common_type_t< T0, T1, Ts...> picked_min(Picker&& pick, T0&& val1, T1&& val2, Ts&&... vs)
  43. {
  44. // if pick doesn't prefer 2 over 1, use 1 -- stability!
  45. if (pick(val2, val1))
  46. return picked_min(std::forward<Picker>(pick), val2, std::forward<Ts>(vs)...);
  47. else
  48. return picked_min(std::forward<Picker>(pick), val1, std::forward<Ts>(vs)...);
  49. }
  50.  
  51. // possibly replace with less<void> in C++1y?
  52. struct lesser {
  53. template<typename LHS, typename RHS>
  54. bool operator()( LHS&& lhs, RHS&& rhs ) const {
  55. return std::less< typename std::decay<my_common_type_t<LHS, RHS>>::type >()(
  56. std::forward<LHS>(lhs), std::forward<RHS>(rhs)
  57. );
  58. }
  59. };
  60. // simply forward to the picked_min function with a smart less than functor
  61. // note that we support unrelated pointers!
  62. template<typename... Ts>
  63. auto min( Ts&&... ts )->decltype( picked_min( lesser(), std::declval<Ts>()... ) )
  64. {
  65. return picked_min( lesser(), std::forward<Ts>(ts)... );
  66. }
  67. }
  68. int main()
  69. {
  70. int x = 7;
  71. int y = 3;
  72. int z = -1;
  73. my_min::min(x, y, z) = 2;
  74. std::cout << x << "," << y << "," << z << "\n";
  75. std::cout << my_min::min(3, 2, 0.9, 2, 5) << std::endl;
  76. std::cout << my_min::min(3., 1.2, 1.3, 2., 5.2) << std::endl;
  77. return 0;
  78. }
  79.  
Success #stdin #stdout 0s 3296KB
stdin
Standard input is empty
stdout
7,3,2
0.9
1.2