将可变参数模板转换为constexpr

时间:2017-02-16 17:36:25

标签: c++ c++14 variadic-templates constexpr c++17

我想知道是否可以将通过参数包调用的简单循环转换为具有更简单代码的constexpr。此示例代码演示了我尝试做的事情

struct Student {
    AgeCategory age;
    Income income; 
    bool is_student;
    CreditRating credit_rating;
    bool buys_computer;
};  

auto find_probability(const double x, const double mean, const double stdev) -> double;

typedef std::tuple<double, double> MeanStdDev;
typedef std::vector<MeanStdDev> MeanStdDevVec;


// This code seems verbose to me. Is there a simpler way to express this
// loop which iterates over a vector and parameter pack, possibly 
// using constexpr. C++14/17 idioms are fine.
template<typename Attr>
auto get_probability(const MeanStdDevVec& v, const size_t n, const Student& s, Attr attr) -> double {
    double mean, stdev;
    std::tie(mean, stdev) = v[n];

    return find_probability(static_cast<double>(std::invoke(attr, s)), mean, stdev);
}

template<typename First, typename... Attr>
auto get_probability(const MeanStdDevVec& v, const size_t n, const Student& s, First f, Attr... attr) -> double {
    double mean, stdev;
    std::tie(mean, stdev) = v[n];

    return find_probability(static_cast<double>(std::invoke(f,s)), mean, stdev) * get_probability(v, n + 1, s, attr...);
}

template<typename ...Attr>
auto calculate_class_probability(const std::map<bool, MeanStdDevVec>& summaries, const Student& s, Attr... attributes) {
    for (const auto& i : summaries) {
        get_probability(i.second, 0L, s, attributes...);
    }
}

来自

 Student s;
 calculate_class_probability(class_summaries, s , &Student::age, &Student::income, &Student::credit_rating, &Student::is_student);

2 个答案:

答案 0 :(得分:1)

它不一定会使代码整体变短,但它确实将可以轻松重用的通用部分分开,并且恕我直言使代码更清晰。在这种特殊情况下,关键是将包映射到某种类型的数组中的函数:

imports: [LazyModule.forRoot()]

在你的情况下,这还不够,因为你想用矢量拉链。因此,对此进行有用的修改,可以使pack元素的整数索引可用并将其传递给函数:

template <class T, class F, class ... Args>
std::array<T, sizeof...(Args)> pack_to_array(F f, Args&& ... args) {
    return {(f(std::forward<Args>(args)))...};
}

现在,您可以像这样使用此功能:

template <class T, class F, class ... Args>
std::array<T, sizeof...(Args)> index_pack_to_array(F f, Args&& ... args) {
    std::size_t i = 0;
    return {(f(i++, std::forward<Args>(args)))...};
}

答案 1 :(得分:0)

不确定您想要什么,但我想您可以丢弃getProbability()并重写calculate_class_probability(),如下所示

template <typename ... Attr>
auto calculate_class_probability
     (std::map<bool, MeanStdDevVec> const & summaries,
      Student const & s, Attr ... attributes)
 {
   using unusedT = int[];

   for ( const auto & i : summaries )
    {
      double       mean, stdev;
      double       prob {1.0};
      std::size_t  n {0};

      (void)unusedT { (std::tie(mean, stdev) = i.second[n++],
                       prob *= find_probability(static_cast<double>(std::invoke(attributes,s)), mean, stdev),
                       0)... };

      // in prob the calculate value
    }
 }

但是:不:我不认为可以将其写成constexpr; operator[]的{​​{1}}不是std::vector<>