C ++ 11: Variadic Uniform arguments to a template function without a POD?

How do you write a template function that takes a variable number of homogeneous arguments to a non-POD function in C ++ 11?

For example, suppose we wanted to write a min function for any type that defines less than the "operator <" as follows:

// pseduo-code...

template<class T...>
T min(T x1, T x2, ..., T xn)
{
    T lowest = x1;

    for (T x : {x2,...,xn})
       if (x < lowest)
           lowest = x;

    return lowest;
}

The above is illegal C ++ 11, how would you write it legally?

+4
source share
4 answers

Homogeneous? Just use itstd::initializer_list .

template <typename T>
T min_impl(std::initializer_list<T> values)
{
    return *std::min_element(values.begin(), values.end());
}

...

return min_impl({8, 5, 4, 1, 6});

(As @Jesse noted , this is equivalent to std :: min in the standard library.)

, , :

template <typename... T>
auto min(T&&... args) -> decltype(min_impl({std::forward<T>(args)...}))
{
    return min_impl({std::forward<T>(args)...});
}

...

return min(8, 5, 1, 4, 6);
+9

-, " ". , , , :

template<typename... Ts> void foo(Ts... ts);

... ( vararg, ). :

template<typename T> void foo(T... t); // error

template<typename T> void foo(T t...); // error

-, , , , for-loop. , "" .

// single argument base case
template<typename T>
void foo(T t) {
    std::cout << t;
}

template<typename T,typename... Us>
void foo(T t,Us... us) {
   foo(t) // handle first argument using single argument base case, foo(T t)
   foo(us...); // 'recurse' with one less argument, until the parameter pack
    // only has one argument, then overload resolution will select foo(T t)
}

, , enable_if "SFINAE", . , :

#include <type_traits>
#include <utility>

template<class T>
T min(T t) {
    return t;
}

template<class T,class... Us>
typename std::common_type<T,Us...>::type
min(T t,Us... us)
{
    auto lowest = min(us...);
    return t<lowest ? t : lowest;
}

int main() {
    min(1,2,3);
}

enable_if, .

template<class T,class... Us>
typename std::enable_if<
    std::is_same<T,typename std::common_type<Us...>::type>::value,
    T>::type
min(T t,Us... us)
{
    auto lowest = min(us...);
    return t<lowest ? t : lowest;
}

, , , is_same.

, , . initializer_list, KennyTM, , . , min max, , , initializer_list.


is_same<T,typename common_type<Us...>::type>?

min(), . , sizeof...(Us) . , , common_type<Us...> , is_same<T,common_type<Us...>> , .

min() min(us...). , Us... , , commont_type<Us...> , , is_same<T,common_type<Us...>> , T .

, , min(a,b) , a b . , min(c,a,b) min(a,b), min(c,a,b) , a b , , c . min(d,c,a,b) min(c,a,b), , min(d,c,a,b) , c, a b , , , d . Etc.

+2

, , :

#include <iostream>
#include <type_traits>

template<typename F, typename T, typename Arg>
auto fold(F f, T&& t, Arg&& a) 
  -> decltype(f(std::forward<T>(t), std::forward<Arg>(a)))
{ return f(std::forward<T>(t), std::forward<Arg>(a)); }

template<typename F, typename T, typename Head, typename... Args>
auto fold(F f, T&& init, Head&& h, Args&&... args) 
  -> decltype(f(std::forward<T>(init), std::forward<Head>(h)))
{ 
  return fold(f, f(std::forward<T>(init), std::forward<Head>(h)), 
              std::forward<Args>(args)...); 
}

// polymorphic less
struct p_less {
  template<typename T, typename U>
  typename std::common_type<T, U>::type 
  operator()(T&& t, U&& u) const {
    return t < u ? t : u;
  }
};

// heterogeneous arguments possible
template<typename Head, typename... Args>
auto min(Head&& h, Args&&... args) -> typename std::common_type<Head, Args...>::type
{
  return fold(p_less(), std::forward<Head>(h), 
              std::forward<Args>(args)...);
}


// only considers homogeneous arguments
template<typename Head, typename... Args>
auto hmin(Head&& h, Args&&... args) -> Head
{
  return fold([](Head x, Head y) -> Head { return x < y ? x : y; }, 
              std::forward<Head>(h), std::forward<Args>(args)...);
}

int main()
{

  double x = 2.0, x2 = 3.0;
  int y = 2;

  auto d1 = min(3, 4.0, 2.f, 6UL);
  auto d2 = min(x, y);
  auto d3 = hmin(x, x2);
  auto b = hmin(3, 2, 7, 10);

  std::cout << d1 << std::endl;
  std::cout << d2 << std::endl;
  std::cout << d3 << std::endl;

  std::cout << b << std::endl;
  return 0;
}

. common_type , . , . boost::variant, , , .

+1

:

template <typename T, typename... T2>
T min(T x1, T2... rest);

template <typename T>
T min(T x)
{
  return x;
}

template <typename T, typename... T2>
T min(T x1, T2... rest)
{
  return std::min (x1, min (rest...));
}

, , , , , int long . , , .

0

All Articles