如何在编译时将相同长度的数组相加?

huangapple go评论122阅读模式
英文:

how do we add up arrarys of the same length at compile time

问题

专家们!我正在考虑如何使用模板编程在编译时使用C++17或C++20完成逐元素数组加法。例如,3个数组 {1,2,3}, {2,4,6}, {3,6,9} 将被相加得到 { 6, 12, 18 }。给定数组中相同索引的所有元素将被相加。以下是我的初始思路。

  1. template <int... I>
  2. struct Seq {};
  3. template <template<int...> typename... Seqs>
  4. struct addSeq{};
  5. int main(){
  6. static_assert(std::is_same_v<addSeq<Seq<1, 2, 3>, Seq<2, 4, 6>, Seq<3, 6, 9>>::type, Seq<6, 12, 18>>);
  7. }

有没有专家能提供一些见解?

我遇到的第一个问题是,如果我为结构体 addSeq 使用这样的模板接口:

  1. template <template<int...> typename... Seqs>

那么我将不得不为每个 Seqs 中的每个 int..T 传递参数给 addSeq{}。我不知道如何设计结构体 addSeq,以便我只能像这样使用它:

  1. addSeq<Seq<1, 2, 3>, Seq<2, 4, 6>, Seq<3, 6, 9>>::type
英文:

experts! I am thinking how to use template programing to finish element-wise array addition at compile time using C++17 or C++20. For example, 3 arrs {1,2,3}, {,2,4,6}, {3,6,9} would be added up to { 6, 12, 18 }. All elements at the same index on the given arrays would be added up. The following is my initial thougt.

  1. template &lt;int... I&gt;
  2. struct Seq {};
  3. template &lt; template&lt;int...&gt; typename...Seqs &gt;
  4. struct addSeq{};
  5. int main(){
  6. static_assert(std::is_same_v&lt;addSeq&lt;Seq&lt;1, 2, 3&gt;,Seq&lt;2, 4, 6&gt;, Seq&lt;3, 6, 9&gt; &gt;::type, Seq&lt;6, 12, 18&gt;&gt;);
  7. }

Any expert could provide some insigh?

the first problem I am running into is if I use such template interface for struct addSeq{}:

  1. template &lt; template&lt;int...&gt; typename...Seqs &gt;

then I would have pass every int..T for every Seqs to addSeq{}. I have no clue how to desgin struct addSeq such that I can only use it like

  1. addSeq&lt;Seq&lt;1, 2, 3&gt;,Seq&lt;2, 4, 6&gt;, Seq&lt;3, 6, 9&gt; &gt;::type

答案1

得分: 2

你仍然可以在编译时使用 std::array,因为它是constexpr友好的(也适用于C++17)。因此,在编译时处理数组的基本构建块仍然是 std::array。所以我认为没有必要通过模板参数来处理值的额外复杂性,然后解决方案看起来像这样:

  1. #include <array>
  2. template<typename type_t, std::size_t N, std::size_t M>
  3. static constexpr auto sum_arrays(const std::array<std::array<type_t, M>, N>& arrays)
  4. {
  5. std::array<type_t, M> sum{};
  6. for (const auto& array : arrays)
  7. {
  8. for (std::size_t index{}; index < M; ++index)
  9. {
  10. sum[index] += array[index];
  11. }
  12. }
  13. return sum;
  14. }
  15. int main()
  16. {
  17. static constexpr std::array<std::array<int, 3>, 4> arrays
  18. {{
  19. {1,2,3},
  20. {4,5,6},
  21. {7,8,9},
  22. {10,11,12}
  23. }};
  24. static constexpr auto sum = sum_arrays(arrays);
  25. static_assert(sum[0] == 22);
  26. static_assert(sum[1] == 26);
  27. static_assert(sum[2] == 30);
  28. return 0;
  29. }

注意:当将该函数移到头文件时,请不要忘记将static constexpr替换为inline constexpr

英文:

You can still work with std::array at compile time since it is constexpr friendly (C++17 also). So the building block for working with arrays at compile time is still std::array. So I see no need to work through the extra complexity of template arguments for your values, and then the solution looks like this:

  1. #include &lt;array&gt;
  2. template&lt;typename type_t, std::size_t N, std::size_t M&gt;
  3. static constexpr auto sum_arrays(const std::array&lt;std::array&lt;type_t, M&gt;, N&gt;&amp; arrays)
  4. {
  5. std::array&lt;type_t, M&gt; sum{};
  6. for (const auto&amp; array : arrays)
  7. {
  8. for (std::size_t index{}; index &lt; M; ++index)
  9. {
  10. sum[index] += array[index];
  11. }
  12. }
  13. return sum;
  14. }
  15. int main()
  16. {
  17. static constexpr std::array&lt;std::array&lt;int, 3&gt;, 4&gt; arrays
  18. {{
  19. {1,2,3},
  20. {4,5,6},
  21. {7,8,9},
  22. {10,11,12}
  23. }};
  24. static constexpr auto sum = sum_arrays(arrays);
  25. static_assert(sum[0] == 22);
  26. static_assert(sum[1] == 26);
  27. static_assert(sum[2] == 30);
  28. return 0;
  29. }

Note : do not forget to replace static constexpr with inline constexpr when moving the function to a header file.

答案2

得分: 0

你可以简单地使用模板部分特化来实现这个:

  1. #include <type_traits>
  2. template <int... I>
  3. struct Seq {};
  4. template <typename... Seqs >
  5. struct addSeq { };
  6. template <typename X, typename Y, typename... Rest>
  7. struct addSeq<X, Y, Rest...> : addSeq<typename addSeq<X, Y>::type, Rest...> { };
  8. template <int... Xs, int... Ys>
  9. struct addSeq<Seq<Xs...>, Seq<Ys...>> {
  10. using type = Seq<(Xs + Ys)...>;
  11. };
  12. static_assert(std::is_same_v<addSeq<Seq<1, 2, 3>, Seq<2, 4, 6>, Seq<3, 6, 9>>::type, Seq<6, 12, 18>>);
英文:

You can simply use template partial specialization to do this:

  1. #include &lt;type_traits&gt;
  2. template &lt;int... I&gt;
  3. struct Seq {};
  4. template &lt;typename...Seqs &gt;
  5. struct addSeq { };
  6. template &lt;typename X, typename Y, typename... Rest&gt;
  7. struct addSeq&lt;X, Y, Rest...&gt; : addSeq&lt;typename addSeq&lt;X, Y&gt;::type, Rest...&gt; { };
  8. template &lt;int... Xs, int... Ys&gt;
  9. struct addSeq&lt;Seq&lt;Xs...&gt;, Seq&lt;Ys...&gt;&gt; {
  10. using type = Seq&lt;(Xs + Ys)...&gt;;
  11. };
  12. static_assert(std::is_same_v&lt;addSeq&lt;Seq&lt;1, 2, 3&gt;,Seq&lt;2, 4, 6&gt;, Seq&lt;3, 6, 9&gt; &gt;::type, Seq&lt;6, 12, 18&gt;&gt;);

huangapple
  • 本文由 发表于 2023年6月9日 12:01:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437126.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定