Sorting C ++ Template

I am looking for template code to sort template parameters like:

template <typename T, typename ... Args>
list<T> sort(T first, Args ... rest)

      

All types in Args are actually T, but I need to use variadic templates so that I can compile temporary lists, like this:

sort(varA, varB, varC, varD).

      

(In fact, I plan on having "all_different" which will sort and remove duplicates to see if all varA, varB, varC, varD values โ€‹โ€‹have different values).

Where would it be written?

+3


source to share


3 answers


This is fairly straightforward to implement, assuming you want to sort the function arguments. Just create a vector (or std::list

if for some reason you want to use it) from the arguments and sort it.

template <typename T, typename ... Args, typename T_d = std::decay_t<T>>
std::vector<T_d> sort(T&& first, Args&&... rest){
    // optionally static assert that all of decay_t<Args>... are the same as T_d

    // build the vector
    std::vector<T_d> ret;
    ret.reserve(1 + sizeof...(Args));
    ret.push_back(std::forward<T>(first));
    using expander = int[];
    (void) expander{0, (ret.push_back(std::forward<Args>(rest)), 0)...};

    // now sort it
    std::sort(ret.begin(), ret.end());
    return ret;
}

      

See this answer for an explanation of how it works expander

.



You can abbreviate "plot vector" in:

std::vector<T_d> ret { std::forward<T>(first), std::forward<Args>(rest)... };

      

but that requires an extra copy for each element (and doesn't work for move-only types) since you can't go from std::initializer_list

.

+5


source


Do one at a time:

template<class R>
R sort_the_range( R&& r ) {
  using std::begin; using std::end;
  std::sort( begin(r), end(r) );
  return std::forward<R>(r);
}

      

some metaprogramming: (hana-style)

template<class T> struct tag{using type=T;};
template<class...> struct types{using type=types;};
template<class Tag>using type_t=typename Tag::type;

template<class Default, class...Ts,
  class=typename std::enable_if<!std::is_same<void,Default>::value>::type
>
constexpr tag<Default> type_from( tag<Default>, Ts... ) { return {}; }
template<class T0, class...Ts>
constexpr tag<T0> type_from( tag<void>, tag<T0>, Ts... ) { return {}; }

template<class Default, class...Ts>
using type_from_t = type_t< decltype( type_from( tag<Default>{}, tag<Ts>{}... ) ) >;

      

now, the function that creates the vector. You can pass the type for the vector, or infer your choice from the first argument:



// explicit T argument is optional:
template<class ExplicitType=void, class...Ts,
  // deduce return type:
  class R=type_from_t<ExplicitType, typename std::decay<Ts>::type...>
>
std::vector<R> make_vector( Ts&&... ts ) {
  // block explicit conversions:
  using test = decltype(std::array<R, sizeof...(Ts)>{{ std::declval<Ts>()... }});
  (void)tag<test>{}; // block warnings
  // make our vector, and size it right:
  std::vector<R> retval;
  retval.reserve( sizeof...(ts) );
  // populate the vector:
  (void)std::initializer_list<int>{0,((
    retval.emplace_back(std::forward<Ts>(ts))
  ),void(),0)...};
  return retval;
}

      

and the line:

template<class T=void, class...Ts>
auto make_sorted_vector(Ts&&...ts)
->decltype( make_vector<T>(std::forward<Ts>(ts)...) )
{
  return sort_the_range(
    make_vector<T>( std::forward<Ts>(ts)... )
  );
}

      

live example )

+1


source


It's simple:

template <typename T, typename... Args>
list<T> sort(const T& first, Args... args)
{
    list<T> result{first, args...};
    result.sort();
    return result;
}

      

-1


source







All Articles