std :: tuple作为模板参数?

时间:2015-05-04 10:48:06

标签: c++ templates c++11

我正在尝试编写一个std::sort模板比较类,它应该接收未知数量的元组(可变参数模板)。每个元组应该由一列(我们的代码中有一些类型)和一个bool组成,指定此列是否应按升序或降序排序。

基本上,我想要类似的东西:

// 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中是否可行?

3 个答案:

答案 0 :(得分:4)

是的,这是可能的 - 你想要Comparator的部分专业化:

template <typename T>
struct Comparator;

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

答案 1 :(得分: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...>;

答案 2 :(得分: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;
};

哨兵班:

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的第一个值从行获取列值 - 所以我假设 - 你知道怎么做 - 所以用你的代码替换这部分。