能否在单个表达式中扩展多个参数包?
Can multiple parameter packs be expanded in a single expression?
我想从两个参数包中得到一个矩阵,如下所示:
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
我该怎么做?
当你有折叠表达式时不需要使用虚拟数组。
天真的 (Print(n1 * n2), ...);
不会工作(它希望包具有相同的大小,并且会打印 N 个数字而不是 N2)。
您需要两个嵌套的折叠表达式。在内部,您可以通过将其中一个包作为 lambda 参数传递来防止其展开。
([](int n){(Print(n1 * n), ...);}(n2), ...);
这不是单个表达式,但您可以展开它并使用 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';
}
};
我假设您代码中的输出是检查编译时评估,因为 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;
}
我想从两个参数包中得到一个矩阵,如下所示:
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
我该怎么做?
当你有折叠表达式时不需要使用虚拟数组。
天真的 (Print(n1 * n2), ...);
不会工作(它希望包具有相同的大小,并且会打印 N 个数字而不是 N2)。
您需要两个嵌套的折叠表达式。在内部,您可以通过将其中一个包作为 lambda 参数传递来防止其展开。
([](int n){(Print(n1 * n), ...);}(n2), ...);
这不是单个表达式,但您可以展开它并使用 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';
}
};
我假设您代码中的输出是检查编译时评估,因为 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;
}