2015-05-04 110 views
3

我正試圖編寫一個std::sort模板比較類,它應該接收未知數量的元組(可變參數模板)。每個元組應包含一列(我們代碼中的某些類型)和一個布爾值,指定該列是按升序還是降序排序。std ::元組作爲模板參數?

基本上,我想類似這樣的東西:

// doesn't compile - conceptual code 
template <typename std::tuple<Col, bool>> 
struct Comparator 
{ 
    bool operator() (int lhs, int rhs) 
    { 
     // lhs and rhs are row indices. Depending on the columns 
     // and the bools received, decide which index should come first 
    } 
} 

是這樣的事情可能在C++ 11?

+0

@BaummitAugen因爲後來我想添加基於列類型的模板專業化(應該有提及) – Shmoopy

+0

不應該'運算符()'採取'元組<>'?這隻能用於排序整數... – Barry

+0

@Barry排序整數,但相對於作爲模板參數傳遞的列(整數表示行索引,列表示列排序) – Shmoopy

回答

4

是的,這是可能的 - 你想要的Comparator部分專業化:

template <typename T> 
struct Comparator; 

template <typename Col> 
struct Comparator<std::tuple<Col, bool>> 
{ 
    // ... 
}; 
0

這可能嗎?是的,但你需要一些相當醜陋的模板技巧。

//a trait for checking if a type is of the form std::tuple<T,bool> 
template <class Tuple> 
struct is_col_bool_tuple : false_type{}; 

template <typename Col> 
struct is_col_bool_tuple<std::tuple<Col,bool>> : true_type{}; 

//a helper struct for checking if all the values in a boolean pack are true 
template<bool...> struct bool_pack; 
template<bool... bs> 
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>; 

//a trait to check if a list of types are all of the form std::tuple<T,bool> 
template <class... Tuples> 
using are_col_bool_tuples = all_true<is_col_bool_tuple<Tuples>::value...>; 

//an incomplete type for when we pass incorrect template arguments 
//this impl helper is needed because variadic parameters need to be last 
template <typename Enable, class... Tuples> 
struct ComparatorImpl; 

//our specialized implementation for when the template arguments are correct 
template <class... Tuples> 
struct ComparatorImpl<std::enable_if_t<are_col_bool_tuples<Tuples...>::value>, 
         Tuples...> 
{ 
    bool operator() (int lhs, int rhs) 
    { 
     //do your comparison 
    } 
}; 

//a nice alias template for forwarding our types to the SFINAE-checked class template 
template <class... Tuples> 
using Comparator = ComparatorImpl<void, Tuples...>; 
+0

downvoter可以解釋這是什麼問題嗎?也許我誤解了這個問題? – TartanLlama

+0

我也不明白這個問題(我沒有downvote) – Barry

0

作爲一般規則,是的,你可以部分專門化可變參數模板。

對於你的情況,我會用這3個專業化:

首先,一般的定義,你可以看到,你不需要定義它的身體:

template <typename ...ColOrderType> 
class Comparator; 

二,中間步驟:

template <typename Col, typename ...ColOrderType> 
struct Comparator<std::tuple<Col,bool>, ColOrderType...> 
    : public Comparator<ColOrderType...> 
{ 
    typedef Comparator<ColOrderType...> Base; 
    Comparator(std::tuple<Col,bool> const& firstOrder, 
       ColOrderType&&... nextOrders) 
     : Base(std::forward<ColOrderType>(nextOrders)...), 
     currectOrder(firstOrder) 
    {} 
    // this is implementation of `operator <` - feel free to change 
    template <typename T> 
    bool operator() (T const& lhs, T const& rhs) 
    { 
     auto&& lcol = get(std::get<0>(currentOrder), lhs); 
     auto&& rcol = get(std::get<0>(currentOrder), rhs); 
     bool order = std::get<1>(currentOrder); 
     if (lcol < rcol) return order; 
     if (rcol < lcol) return not order; 
     return Base::operator()(lhs, rhs); 
    } 
    std::tuple<Col,bool> currentOrder; 
}; 

和Sentinel類:

template <> 
struct Comparator<> 
{ 
    template <typename T> 
    bool operator() (T const& lhs, T const& rhs) 
    { 
     return false; 
    } 
}; 

請注意,您將無法傳遞除兩個元素的std :: tuple之外的類型 - Comparator的定義不允許它 - 這就是爲什麼一般定義未定義的原因。

而在這部分約get功能:

 auto&& lcol = get(std::get<0>(currentOrder), lhs); 
     auto&& rcol = get(std::get<0>(currentOrder), rhs); 

我不知道你怎麼從行獲得列值基礎上的第一個值傳遞tuple - 所以我想 - 你知道該怎麼做它 - 用你的代碼替換這部分。