部分类模板专业化c ++ 11

时间:2016-04-01 09:29:08

标签: c++ templates c++11 specialization

我正在尝试编译以下代码,但我收到错误:

  

模板参数数量错误

template<int start, int end, int step>
struct range{};

template<int start, int end>
struct range<start, end, 1>{};

template<int end>
struct range<0, end, 1>{};

int main() {
    auto r1 = range<0, 5, 2>{};
    auto r2 = range<5, 15>{}; //error: wrong number of template arguments
    auto r3 = range<10>{}; //error: wrong number of template arguments
}

如何创建部分模板类对象?

2 个答案:

答案 0 :(得分:4)

您需要根据主模板的声明指定所有模板参数,然后根据模板参数确定选择的参数。

auto r1 = range<0, 5, 2>{};  // the primary template
auto r2 = range<5, 15, 1>{}; // the 1st partial specified template
auto r3 = range<0, 10, 1>{}; // the 2nd partial specified template

如果要指定较少的模板参数,可能需要default template arguments

template<int end, int start = 0, int step = 1>
struct range{};

auto r1 = range<5, 0, 2>{}; // end->5, start->0, step->2
auto r2 = range<15, 5>{};   // end->15, start->5, step->1
auto r3 = range<10>{};      // end->10, start->0, step->1

请注意,我更改了模板参数的顺序,因为如果为模板参数指定了默认参数,则每个后续模板参数也必须具有默认参数。

答案 1 :(得分:4)

如果您希望能够在start之前指定end,还要为start指定默认参数,则可以执行以下操作:

template <int... Args>
struct range {
    static_assert(sizeof...(Args) > 0 && sizeof...(Args) <= 3, 
                  "Must pass 1-3 args");

    using ArgPack = std::tuple<std::integral_constant<int, Args>...>;

    template <int Size, typename Then, typename Else>
    using select_value = typename std::conditional_t<
         (sizeof...(Args) > Size), Then, Else
    >::type;

    static constexpr int start = select_value<1,
        std::tuple_element<0, ArgPack>, std::integral_constant<int,0>
    >::value;

    static constexpr int end = select_value<1, 
        std::tuple_element<1, ArgPack>, std::tuple_element<0, ArgPack>
    >::value;

    static constexpr int step = select_value<2, 
        std::tuple_element<2, ArgPack>, std::integral_constant<int,1>
    >::value;
};

这正是您所希望的用法,例如:

int main()
{
   using a = range<1,1,2>;
   static_assert(a::start == 1 && a::end == 1 && a::step == 2, "wat");

   using b = range<1,1>;
   static_assert(b::start == 1 && b::end == 1 && b::step == 1, "wat");

   using c = range<3>;
   static_assert(c::start == 0 && c::end == 3 && c::step == 1, "wat");
}

Live Demo