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

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

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 }。给定数组中相同索引的所有元素将被相加。以下是我的初始思路。

template <int... I>
struct Seq {};

template <template<int...> typename... Seqs>
struct addSeq{};

int main(){

    static_assert(std::is_same_v<addSeq<Seq<1, 2, 3>, Seq<2, 4, 6>, Seq<3, 6, 9>>::type, Seq<6, 12, 18>>);

}

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

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

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

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

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.

template &lt;int... I&gt;
struct Seq {};

template &lt; template&lt;int...&gt; typename...Seqs &gt;
struct addSeq{};

int main(){

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

}

Any expert could provide some insigh?

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

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

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。所以我认为没有必要通过模板参数来处理值的额外复杂性,然后解决方案看起来像这样:

#include <array>

template<typename type_t, std::size_t N, std::size_t M>
static constexpr auto sum_arrays(const std::array<std::array<type_t, M>, N>& arrays)
{
    std::array<type_t, M> sum{};

    for (const auto& array : arrays)
    {
        for (std::size_t index{}; index < M; ++index)
        {
            sum[index] += array[index];
        }
    }

    return sum;
}

int main()
{
    static constexpr std::array<std::array<int, 3>, 4> arrays
    {{
        {1,2,3},
        {4,5,6},
        {7,8,9},
        {10,11,12}
    }};

    static constexpr auto sum = sum_arrays(arrays);

    static_assert(sum[0] == 22);
    static_assert(sum[1] == 26);
    static_assert(sum[2] == 30);

    return 0;
}

注意:当将该函数移到头文件时,请不要忘记将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:

#include &lt;array&gt;

template&lt;typename type_t, std::size_t N, std::size_t M&gt;
static constexpr auto sum_arrays(const std::array&lt;std::array&lt;type_t, M&gt;, N&gt;&amp; arrays)
{
	std::array&lt;type_t, M&gt; sum{};

	for (const auto&amp; array : arrays)
	{
		for (std::size_t index{}; index &lt; M; ++index)
		{
			sum[index] += array[index];
		}
	}

	return sum;
}

int main()
{
	static constexpr std::array&lt;std::array&lt;int, 3&gt;, 4&gt; arrays
	{{
		{1,2,3},
		{4,5,6},
		{7,8,9},
		{10,11,12}
	}};

	static constexpr auto sum = sum_arrays(arrays);

	static_assert(sum[0] == 22);
	static_assert(sum[1] == 26);
	static_assert(sum[2] == 30);

	return 0;
}

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

答案2

得分: 0

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

#include <type_traits>

template <int... I>
struct Seq {};

template <typename... Seqs >
struct addSeq { };

template <typename X, typename Y, typename... Rest>
struct addSeq<X, Y, Rest...> : addSeq<typename addSeq<X, Y>::type, Rest...> { };

template <int... Xs, int... Ys>
struct addSeq<Seq<Xs...>, Seq<Ys...>> {
  using type = Seq<(Xs + Ys)...>;
};

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:

#include &lt;type_traits&gt;

template &lt;int... I&gt;
struct Seq {};

template &lt;typename...Seqs &gt;
struct addSeq { };

template &lt;typename X, typename Y, typename... Rest&gt;
struct addSeq&lt;X, Y, Rest...&gt; : addSeq&lt;typename addSeq&lt;X, Y&gt;::type, Rest...&gt; { };

template &lt;int... Xs, int... Ys&gt;
struct addSeq&lt;Seq&lt;Xs...&gt;, Seq&lt;Ys...&gt;&gt; {
  using type = Seq&lt;(Xs + Ys)...&gt;;
};

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:

确定