首页 > 解决方案 > 指定类模板参数的要求

问题描述

我有几个看起来像这样的课程:

struct neg_inf {
    constexpr double operator()() { return -std::numeric_limits<double>::infinity(); }
};

struct pos_inf {
    constexpr double operator()() { return std::numeric_limits<double>::infinity(); }
};

template<typename dX, class LowerBound, class UpperBound>
class limit {
    dX dx;
    UpperBound upperBound;
    LowerBound lowerBound;
    double step_size;

    limit( dX x, LowerBound lower, UpperBound upper, double step = 1 ) :
        dx{ x }, lowerBound{ lower }, upperBound{ upper }, step_size{ step }
    {}

    dX value() const { return dx; }
    LowerBound lower() const { return lowerBound; }
    UpperBound upper() const { return upperBound; }
    double step() const { return step_size; }            
};

到目前为止,这些类按预期工作。现在我想使用诸如std::enable_if_t,之类的条件来修改模板参数std::is_arithemtic std::is_same

这些是实例化限制对象需要满足的条件。

  • dX必须至少arithmeticnumerical
  • Lower&Upper bound必须是numericalarithmeticneg_infpos_inf

例如,这些是有效的实例化:

dX = 1st and can be any: int, long, float, double, /*complex*/, etc.

limit< 1st, 1st, 1st >     // default template

limit< 1st, 1st, pos_inf >  // these will be specializations
limit< 1st, 1st, neg_inf >
limit< 1st, pos_inf, 1st >
limit< 1st, neg_inf, 1st >
limit< 1st, pos_inf, pos_inf >
limit< 1st, neg_inf, neg_inf >
limit< 1st, neg_inf, pos_inf >
limit< 1st, pos_inf, neg_inf >

这些是实例化我的模板的有效条件。UpperBound当and orLowerBound是一种infinity类型时,我计划部分专业化这门课。当upperlower边界是数值 - 算术类型时,通用或默认模板将处理它们。

我的问题是图书馆template declaration的班级会是什么样子?type_traits

标签: c++templatesc++17template-specialization

解决方案


将模板类型限制为类的一种方法是为 SFINAE 添加额外的参数:

template <typename dX, class LowerBound, class UpperBound, typename Enabler = void>
class limit;

然后,通过适当的 SFINAE 提供专业化

template <typename dX, class LowerBound, class UpperBound>
class limit<dX,
            LowerBound,
            UpperBound,
            std::enable_if_t<my_condition<dX, LowerBound, UpperBound>::value>>
{
    // ...
};

所以在你的情况下,my_condition应该是这样的

template <typename dX, class LowerBound, class UpperBound>
using my_condition =
    std::conjunction<std::is_arithmetic<dX>,
                     std::disjunction<std::is_arithmetic<LowerBound>,
                                      std::is_same<LowerBound, neg_inf>,
                                      std::is_same<LowerBound, pos_inf>>,
                      std::disjunction<std::is_arithmetic<UpperBound>,
                                       std::is_same<UpperBound, neg_inf>,
                                       std::is_same<UpperBound, pos_inf>>
                      >;

另一种方式是static_assert

template <typename dX, class LowerBound, class UpperBound>
class limit
{
    static_assert(std::is_arithmetic<dX>::value, "!");
    static_assert(std::is_arithmetic<LowerBound>::value
                  || std::is_same<LowerBound, neg_inf>::value
                  || std::is_same<LowerBound, pos_inf>::value, "!");
    static_assert(std::is_arithmetic<UpperBound>::value
                  || std::is_same<UpperBound, neg_inf>::value
                  || std::is_same<UpperBound, pos_inf>::value, "!");
    // ...
};

推荐阅读