2015-06-16 44 views
3

我找模板代码模板参数排序,是这样的:C++模板排序

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

所有在args的类型实际上是T,但我需要使用可变参数模板,让我可以小编译像时间列表:

sort(varA, varB, varC, varD). 

(事实上,我打算在具有“all_different”,这将进行排序,并删除重复,以驴如果4个值内翻,varB,VARC,varD都是不同的)。

任何地方这种类型已经写好了?

+1

有什么理由不在这里使用initializer_list,比如说,有一个像sort({varA,varB,varC,varD})这样的排序例程? – templatetypedef

+1

你实际上并没有对模板参数进行排序('T,Args ...'),对吧?你想实际排序'首先,休息...'? @templatetypedef这将强制一个副本。这一个不必如果与转发参考正确地撒上。 –

回答

5

假设您想对函数参数进行排序,实现起来相当简单。只需从参数中构建一个矢量(或者一个std::list,如果因为任何原因您想使用它)并对其进行分类。

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; 
} 

如何expander作品的说明,请参见this answer

可以缩写“打造载体”的部分为:

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

但这招致每个元件的额外拷贝(和布展只种不工作),因为你不能从移动一个std::initializer_list

+0

让函数只接受“Args && ...”并使用可变类型函数获得T是否更明确?这将例如消除“保留”的“1 +”和单独的“push_back”。简单类型函数实现:template struct Head {static_assert(sizeof ...(Args)!= 0,“没有为'Head'指定类型); }; template struct Head {using type = T; }; –

+0

什么,没有'emplace'! 'push_back'可以给你一个不需要的副本。 ;) – Yakk

+0

@Yakk在类型不匹配?所以吧(这将是一个举动)。我不想允许明确的转换。 –

-1

这个简单:

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

downvote的原因? –

+0

我没有downvote,但这会招致额外的副本。 –

1

做一两件事的时间:

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); 
} 

一些元编程:(花样式)

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>{}...)) >; 

现在,一个函数,使一个向量。你可以在一个类型传递的载体,或者它的第一个参数推断,你的选择:

// 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; 
} 

和缝合:

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

+0

你仍然从初始化列表中做一个额外的拷贝:) –

+1

@ T.C。点。哇,这个代码在C++ 14和C++ 1z中变得更干净。 C++ 14允许您将工作打包到自动lambda中。 C++ 1z给你折叠表达式。 – Yakk