【问题标题】:Iterate through std::initializer_list遍历 std::initializer_list
【发布时间】:2020-06-11 06:36:17
【问题描述】:
//parameter pack sum example

constexpr int sum(int N= 0)
{
    return N;
}
template<typename ...Args>
constexpr int sum(int first, int second, Args ...N)
{
    return first + second + sum(N...);
}

int main()
{
    std::cout << sum<int>(1,6,3);
}

是否有可能在编译时使用std::initializer_list&lt;int&gt; 得出这个总和,我如何通过这个迭代递归。

【问题讨论】:

  • 你这里没有std::initializer_list&lt;int&gt;。
  • 你真的只限于 C++11,(un)folding pack 语法在以后的版本中已经改进了很多。
  • 对于编译时,您还需要constexpr(标准的后续版本也允许更轻松地编写它们)。
  • 您能更详细地解释一下 parameter_pack 和 std::initializer_list 之间的区别吗?每个的用例是什么?
  • template&lt;typename ...Args&gt; 是参数包,std::initializer_list&lt;T&gt; 是 ...initializer_list ;)。呼叫从 sum_pack(1, 2, 3, 4, 5) 更改为 sum_ini({1, 2, 3, 4, 5})。参数包允许非同质类型所以template &lt;typename...Ts&gt; void print(const Ts&amp;...); print(42, "Hi", 5.3);

标签: c++ c++11 metaprogramming initializer-list parameter-pack


【解决方案1】:

sum 和 std::initializer_list 在 C++11 中可以通过以下方式完成:

template <typename It>
constexpr int sum(It it, It end)
{
    return it == end ? 0 : (*it + sum(it + 1, end));
}

constexpr int sum(std::initializer_list<int> ini)
{
    return sum(ini.begin(), ini.end());
}

static_assert(sum({1, 2, 3, 4, 5})== 15, "!");

Demo

C++14 允许 constexpr 函数中的循环允许摆脱递归:

constexpr int sum(std::initializer_list<int> ini)
{
    int res = 0;
    for (int e : ini) {
        res += e;
    }
    return res;
}

而在 C++20 中,std::accumulate 被标记为 constexpr,允许

constexpr int sum(std::initializer_list<int> ini)
{
    return accumulate(ini.begin(), ini.end(), 0);
}

【讨论】:

    【解决方案2】:

    从 C++20 开始,您可以使用std::reduce,因为它被标记为constexpr:

    #include <initializer_list>
    #include <numeric>
    
    constexpr int sum(std::initializer_list<int> init) {
       return std::reduce(init.begin(), init.end());
    }
    

    【讨论】:

      【解决方案3】:

      这是一个更纯粹的解决方案,没有初始化列表和 constexpr。适用于部分 C++11 支持的 gcc-4.4:

      #include <iostream>
      
      template<int N, int ...Args>
      struct SumImpl
      {
        enum { RESULT = N + SumImpl<Args...>::RESULT };
      };
      
      template<>
      struct SumImpl<0>
      {
        enum { RESULT = 0 };
      };
      
      template<int ...Args>
      struct Sum
      {
        enum { RESULT = SumImpl<Args..., 0>::RESULT };
      };
      
      int main()
      {
        std::cout << Sum<1,6,0,3,23>::RESULT << "\n";
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-12
        • 1970-01-01
        • 2013-08-12
        • 1970-01-01
        • 2015-10-22
        相关资源
        最近更新 更多