【问题标题】:Convert variadic template to constexpr将可变参数模板转换为 constexpr
【发布时间】:2017-02-16 17:36:25
【问题描述】:

我想知道是否可以使用更简单的代码将通过参数包调用的简单循环转换为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);

【问题讨论】:

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


    【解决方案1】:

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

    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)))...};
    }
    

    在您的情况下,这还不够,因为您想用矢量压缩它。因此,一个有用的修改是使 pack 元素的整数索引可用并将其传递给函数:

    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)))...};
    }
    

    现在,你可以像这样使用这个函数:

    template<typename... Attr>
    double get_probability(const MeanStdDevVec& v, const Student& s, Attr... attr) {
    
        assert(v.size() == sizeof...(Attr));
        auto probs = index_pack_to_array<double>(
            [&] (std::size_t i, auto&& a) -> double { 
                return // ... (get probability from v[i], s, and a)
            },
            std::forward<Attr>(attr)...);
    
        return std::accumulate(probs.begin(), probs.end(), 1.0,
            [] (double p1, double p2) { return p1 * p2; });
    }
    

    【讨论】:

    • @Ronnie 谢谢!如果您觉得它回答了您的问题,请将其标记为已接受(打勾)。干杯。
    【解决方案2】:

    不确定你想要什么,但我想你可以扔掉你的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
        }
     }
    

    但是:不:我认为不可能写成constexprstd::vector&lt;&gt;operator[] 不是 constexpr

    【讨论】:

      猜你喜欢
      • 2017-08-07
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      • 2013-10-13
      • 1970-01-01
      相关资源
      最近更新 更多