如何编写一个接受数组 <double, N> 的可变数并推导 N 的函数?
How to write a function that takes a variadic number of array<double, N> and deduce N?
我们的目标是拥有一个函数,该函数接受任意数量的任意大小的数组(但这对所有数组都相同),并在函数体内提供 N。例如,假设我想 return 另一个用户定义的数组类型,使用 N,MyArray。我希望它更清楚!谢谢 我是可变参数模板的新手,不知道该怎么做。任何帮助或提示表示赞赏。谢谢
#include <array>
using namespace std;
template<int N>
struct MyArray {};
// here I don't know how to deduce N and keep the variadic number of parameters
template<int N, typename... Ts>
MyArray<N> foo(const Ts&... ts)
{
// somehow use the variadic parameters
MyArray<N> a;
return a;
}
int main()
{
array<double, 3> a, b, c;
auto d = foo(a, b, c);
}
我不完全确定我是否理解您的函数要做什么。我猜它是“对所有数组求和并将 N 加到每个字段”,如果不是,无论如何我的示例应该是一个很好的说明。
template<size_t N, typename... Ts>
std::array<double, N> foo(std::array<double, N> first)
{
for (size_t i = 0; i < N; ++i) {
first[i] += N;
}
return first;
}
template<size_t N, typename... Ts>
std::array<double, N> foo(const std::array<double, N>& first, Ts&... ts)
{
std::array<double, N> result = foo(ts...);
for (size_t i = 0; i < N; ++i) {
result[i] += first[i];
}
return result;
}
template<size_t N>
void print_array(const std::array<double, N>& arr) {
for (double x : arr) {
std::cout<<x<<" ";
}
std::cout<<"\n";
}
int main() {
std::array<double, 3> a = {1, 2, 3};
std::array<double, 3> b = {4, 5, 6};
std::array<double, 3> c = {7, 8, 9};
auto d = foo(a, b, c);
print_array(d);
d = foo(a, b);
print_array(d);
}
我想你可以接受 std::array
的序列,推导尺寸,只有尺寸一致时 SFINAE 才启用该功能。
我的意思是……
template <std::size_t N0, std::size_t ... Ns,
std::enable_if_t<((N0 == Ns) && ...), int> = 0>
auto foo (std::array<double, N0> const & a0,
std::array<double, Ns> const & ... as)
{
std::array<double, N0> d;
d[0] = (a0[0] + ... + as[0]);
d[0] += N0;
return d;
}
或
template <std::size_t ... Ns, std::size_t N = (Ns + ...)/sizeof...(Ns),
std::enable_if_t<((N == Ns) && ...), int> = 0>
auto foo (std::array<double, Ns> const & ... as)
{
std::array<double, N> d;
d[0] = (N + ... + as[0]);
return d;
}
或者,如果您愿意,推导第一个大小并强加以下类型是相同的
template <std::size_t N0, typename ... Ts,
std::enable_if_t<((std::is_same_v<std::array<double, N0>, Ts>) && ...), int> = 0>
auto foo (std::array<double, N0> const & a0, Ts const & ... as)
{
std::array<double, N0> d;
d[0] = (a0[0] + ... + as[0]);
d[0] += N0;
return d;
}
正如 François Andrieux 所指出的,您可以按照 static_assert()
的方式代替 SFINAE 方式,以获得更有意义的消息错误
template <std::size_t N0, std::size_t ... Ns>
auto foo (std::array<double, N0> const & a0,
std::array<double, Ns> const & ... as)
{
static_assert( ((N0 == Ns) && ...), "some clear error message!");
// ...
但是,通过这种方式,您无法开发 foo()
的不同版本和替代版本。
看看哪个解决方案对你更有用
我终于成功了,仍然不好的是 Foo 的模板部分中 N 的类型必须与 std::array 中使用的类型完全匹配以指示大小,这使得 N 已知里面,可以用来制作一个 MyArray 对象。
基本上我必须将参数包声明为一个模板(因此有一个带有模板包的模板)。 Ts... 在那里是因为数组通常需要 2 个以上的模板参数。
#include <array>
using namespace std;
template<int N>
struct MyArray {};
template<typename T, long unsigned N, typename... Ts, template<typename, long unsigned, typename...> typename... Arrays>
MyArray<N> Foo(const Arrays<T, N, Ts...>&... arrays)
{
return MyArray<N>{};
}
int main()
{
array<double, 3> a, b, c;
MyArray<3> d = Foo(a, b, c);
auto e = Foo(a, b);
return 0;
}
我们的目标是拥有一个函数,该函数接受任意数量的任意大小的数组
#include <array>
using namespace std;
template<int N>
struct MyArray {};
// here I don't know how to deduce N and keep the variadic number of parameters
template<int N, typename... Ts>
MyArray<N> foo(const Ts&... ts)
{
// somehow use the variadic parameters
MyArray<N> a;
return a;
}
int main()
{
array<double, 3> a, b, c;
auto d = foo(a, b, c);
}
我不完全确定我是否理解您的函数要做什么。我猜它是“对所有数组求和并将 N 加到每个字段”,如果不是,无论如何我的示例应该是一个很好的说明。
template<size_t N, typename... Ts>
std::array<double, N> foo(std::array<double, N> first)
{
for (size_t i = 0; i < N; ++i) {
first[i] += N;
}
return first;
}
template<size_t N, typename... Ts>
std::array<double, N> foo(const std::array<double, N>& first, Ts&... ts)
{
std::array<double, N> result = foo(ts...);
for (size_t i = 0; i < N; ++i) {
result[i] += first[i];
}
return result;
}
template<size_t N>
void print_array(const std::array<double, N>& arr) {
for (double x : arr) {
std::cout<<x<<" ";
}
std::cout<<"\n";
}
int main() {
std::array<double, 3> a = {1, 2, 3};
std::array<double, 3> b = {4, 5, 6};
std::array<double, 3> c = {7, 8, 9};
auto d = foo(a, b, c);
print_array(d);
d = foo(a, b);
print_array(d);
}
我想你可以接受 std::array
的序列,推导尺寸,只有尺寸一致时 SFINAE 才启用该功能。
我的意思是……
template <std::size_t N0, std::size_t ... Ns,
std::enable_if_t<((N0 == Ns) && ...), int> = 0>
auto foo (std::array<double, N0> const & a0,
std::array<double, Ns> const & ... as)
{
std::array<double, N0> d;
d[0] = (a0[0] + ... + as[0]);
d[0] += N0;
return d;
}
或
template <std::size_t ... Ns, std::size_t N = (Ns + ...)/sizeof...(Ns),
std::enable_if_t<((N == Ns) && ...), int> = 0>
auto foo (std::array<double, Ns> const & ... as)
{
std::array<double, N> d;
d[0] = (N + ... + as[0]);
return d;
}
或者,如果您愿意,推导第一个大小并强加以下类型是相同的
template <std::size_t N0, typename ... Ts,
std::enable_if_t<((std::is_same_v<std::array<double, N0>, Ts>) && ...), int> = 0>
auto foo (std::array<double, N0> const & a0, Ts const & ... as)
{
std::array<double, N0> d;
d[0] = (a0[0] + ... + as[0]);
d[0] += N0;
return d;
}
正如 François Andrieux 所指出的,您可以按照 static_assert()
的方式代替 SFINAE 方式,以获得更有意义的消息错误
template <std::size_t N0, std::size_t ... Ns>
auto foo (std::array<double, N0> const & a0,
std::array<double, Ns> const & ... as)
{
static_assert( ((N0 == Ns) && ...), "some clear error message!");
// ...
但是,通过这种方式,您无法开发 foo()
的不同版本和替代版本。
看看哪个解决方案对你更有用
我终于成功了,仍然不好的是 Foo 的模板部分中 N 的类型必须与 std::array 中使用的类型完全匹配以指示大小,这使得 N 已知里面,可以用来制作一个 MyArray 对象。
基本上我必须将参数包声明为一个模板(因此有一个带有模板包的模板)。 Ts... 在那里是因为数组通常需要 2 个以上的模板参数。
#include <array>
using namespace std;
template<int N>
struct MyArray {};
template<typename T, long unsigned N, typename... Ts, template<typename, long unsigned, typename...> typename... Arrays>
MyArray<N> Foo(const Arrays<T, N, Ts...>&... arrays)
{
return MyArray<N>{};
}
int main()
{
array<double, 3> a, b, c;
MyArray<3> d = Foo(a, b, c);
auto e = Foo(a, b);
return 0;
}