【问题标题】:Cumulative Product of Template Parameter Pack模板参数包累计产品
【发布时间】:2016-05-22 11:14:14
【问题描述】:

我正在尝试使用模板参数包的累积乘积初始化静态和常量数组:

template <int ...D>
class Foo
{
     static const std::array<const Size, sizeof...(D)> _array;
};
template <int...D> const std::array<const int, sizeof...(D)> Foo<D...>::_array = 
{ cumulative_product<D...>() };

如何编写函数cumulative_product(),以便将D...转换为D...的累积积?例如

Foo<1,2,3,4>::_array;// = {1,1*2,1*2*3,1*2*3*4} = {1,2,6,24}. 

解决方案:非常感谢 @bogdan 提供出色的 C++14 解决方案,以及对我的 C++11 解决方案的改进。

#include <array>
#include <iostream>

#define CPP_VERSION 11

#if CPP_VERSION >= 14

// Credit: @bogdan at http://stackoverflow.com/q/37373602/6367128
template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product(int seed = 1) { return{ { seed *= Args ... } }; }

#elif CPP_VERSION == 11

// Acknowledgement: Huge thank you to @bogdan for making the code more portable, concise and readable!
namespace details
{
   template<int N, int i, int j, int ...Args> struct c_product_gen               // N counts down to zero
   {
      static constexpr std::array<int, sizeof...(Args)+1> get() { return c_product_gen<N - 1, i*j, Args..., i*j>::get(); }
   };
   template<int i, int j, int ...Args> struct c_product_gen<0, i, j, Args...>    // The end point of the template recursion
   {
      static constexpr std::array<int, sizeof...(Args)+1> get() { return { { j, Args... } }; }
   };
}

template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product() { return details::c_product_gen<sizeof...(Args), 1, Args...>::get(); }

#else // CPP_VERSION < 11

template<int... Args> constexpr std::array<int, sizeof...(Args)> cumulative_product() 
{ 
    static_assert(false, "C++ version 11 or greater is required.");
    return std::array<int, sizeof...(Args)>();
}

#endif

int main()
{
   constexpr auto a = cumulative_product<1,2,3,4,5>();
   for(auto i : a) std::cout << i << ' ';    // Output: 1 2 6 24 120 
   std::cout << '\n';  
}

【问题讨论】:

  • @PiotrSkotnicki 是的,绝对的。
  • 我喜欢参数的轮换,不错!请注意,在迂腐模式下的 Clang 和 GCC 会抱怨一些模板技术问题,这些技术问题值得修复以实现最大的可移植性和标准一致性。特别是,GCC 和 EDG 正确地捕获了 Clang 和 MSVC 忽略的一个重要问题 - c_product_gen 的部分特化需要比主模板更特化。顺便说一句,修复这使得remove_first 变得不必要。 Here's a version 进行所有调整。
  • @bogdan 你的改进太棒了:) 非常感谢!我已经用你的改进更新了我的答案,并试图适当地赞扬你(如果我做错了,请告诉我)。再次感谢!

标签: c++ templates c++14 variadic-templates template-meta-programming


【解决方案1】:
#include <array>
#include <utility>
#include <cstddef>

template <int... D, std::size_t... Is>
constexpr std::array<int, sizeof...(D)> cumulative_product(std::index_sequence<Is...>)
{
    static_assert(sizeof...(D), "Missing initializers");
    int a[]{ D... };
    for (int i = 1; i < int(sizeof...(D)); ++i)
    {
        a[i] *= a[i-1];
    }
    return {{ a[Is]... }};
}

template <int... D>
constexpr auto cumulative_product()
{
    return cumulative_product<D...>(std::make_index_sequence<sizeof...(D)>{});
}

template <int... D>
struct Foo
{
     static constexpr std::array<int, sizeof...(D)> _array  = cumulative_product<D...>();
};

DEMO

【讨论】:

  • 非常感谢您的出色回答!只是出于好奇,你怎么能只用 C++11 来做呢?还是不可能?
  • 对于 C++14,即使像 template&lt;int... Ds&gt; constexpr std::array&lt;int, sizeof...(Ds)&gt; cumulative_product(int seed = 1) { return {{seed *= Ds ...}}; } 这样简单的东西也足够了。 @Judge:C++11 解决方案绝对是可能的,但我认为您无法避免使用递归来伪造迭代,而且真的不值得麻烦。
  • @bogdan 我不得不说你的解决方案简直太棒了。
猜你喜欢
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 2014-08-07
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 2020-11-12
  • 1970-01-01
相关资源
最近更新 更多