【问题标题】:Can multiple parameter packs be expanded in a single expression?可以在单个表达式中扩展多个参数包吗?
【发布时间】:2022-01-04 17:56:02
【问题描述】:

我想从两个参数包中获取一个矩阵,如下所示:


template < typename T1, typename T2 > struct Multi{};
template < int ... n > struct N{};

void Print( int n ){ std::cout << n << std::endl; }

template < int ... n1, int ... n2 >
struct Multi< N<n1...>, N<n2...>> 
{
    Multi() 
    {   
        using expander = int[];

        // No idea which syntax should be used here:
        expander{ 0,((void)Print(n1...*n2),0)... };
    }
};


int main()
{
    Multi< N<1,2,3,4>, N< 10,20> >{};
}

结果应该是

10 20 30 40 20 40 60 80

我该怎么做?

【问题讨论】:

  • @S.M.这在部分专业化中是允许的。
  • @S.M.在专业化中允许...适用于当前的 gcc。怎么了?
  • ::std::integer_sequence 可以用来代替N。部分特化中模板参数包中的数字可以打包到数组中/使用fold expression 打印。我不知道为什么Mirror 在这里。
  • 根据您的需要,在 range-v3 中使用 views::cartesian_product 可能会更清晰、更自然。据我了解,完全是constexpr

标签: c++ templates parameter-pack


【解决方案1】:

当你有折叠表达式时,不需要使用虚拟数组。

幼稚的(Print(n1 * n2), ...); 不起作用(它希望包具有相同的大小,并且会打印 N 个数字而不是 N2)。

您需要两个嵌套的折叠表达式。在内部,您可以通过将其中一个包作为 lambda 参数传递来防止其展开。

([](int n){(Print(n1 * n), ...);}(n2), ...);

【讨论】:

    【解决方案2】:

    这不是单一的表达式,但你可以扩展它并使用for循环

    template < int ... n1, int ... n2 >
    struct Multi< N<n1...>, N<n2...>> 
    {
        Multi() 
        {
            for(auto j : {n2...})
            for(auto i : {n1...})
               std::cout << i*j << '\n';
        }
    };
    

    WandBox

    【讨论】:

      【解决方案3】:

      我假设您代码中的输出是检查编译时评估,因为 std::cout 的输出仅在运行时有效。

      另一种选择是不使用结构,而是使用 constexpr 函数, 它们看起来更像普通的 c++ 代码。并且您可以在编译时使用 static_asserts 验证正确性。我确实在示例末尾添加了一些输出 现场演示:https://onlinegdb.com/iNrqezstg

      #include <array>
      #include <iostream>
      
      template<int... n>
      constexpr auto array()
      { 
          return std::array<int,sizeof...(n)>{n...}; 
      };
      
      template<std::size_t N, std::size_t M>
      constexpr auto multiply(const std::array<int, N>& arr1, const std::array<int, M>& arr2)
      {
          std::array<int, N* M> result{};
          std::size_t index{ 0 };
          for (std::size_t n = 0; n < N; n++)
          {
              for (std::size_t m = 0; m < M; m++)
              {
                  result[index] = arr1[n] * arr2[m];
                  ++index;
              }
          }
          return result;
      }
      
      template<typename container_t>
      void show(const char* msg, const container_t& values)
      {
          std::cout << msg << " : ";
          bool comma{ false };
          for (const auto& value : values)
          {
              if (comma) std::cout << ", ";
              std::cout << value;
              comma = true;
          }
      
          std::cout << "\n";
      }
      
      
      int main()
      {
          constexpr auto arr1 = array<1, 2, 3, 4>();
          constexpr auto arr2 = array<10, 20>();
          constexpr auto result = multiply(arr1, arr2);
      
          static_assert(arr1[0] == 1, "");
          static_assert(arr2[1] == 20, "");
          static_assert(result[0] == 10, "");
          static_assert(result[1] == 20, "");
          static_assert(result[6] == 40, "");
      
          show("arr1", arr1);
          show("arr2", arr2);
          show("result", result);
      
          return 0;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-08-25
        • 2018-10-20
        • 1970-01-01
        • 2017-02-01
        • 2012-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多