是否可以定义模板参数包数组
Is it possible to define a template parameter pack array
可能重复:Is it possible to "store" a template parameter pack without expanding it?
与上述问题类似,我想进一步探讨这个问题并存储一个可变数组。
template<size_t N, typename... Args>
void foo(Args(&...args)[N]) {
Args[N]... args2; // compilation error
}
这有可能实现吗?
最终目标是能够调用 foo()
,改变其可变数组输入的副本,并在突变上执行一些函数。所以,像这样:
template<typename F, size_t N, typename... Args>
void applyAsDoubled(F f, Args(&...args)[N]) {
Args[N]... args2;
doublerMutation(args2...); // doubles each argument; external function, assume it cannot avoid having a side-effect on its parameters
for (int i = 0; i < N; i++)
f(args2[i]...);
}
将被调用并且没有副作用:
int A[N] = { 1, 2, 3, 4, 5 };
int B[N] = { 2, 2, 2, 2, 2 };
applyAsDoubled(printAdded, A, B);
将打印 6、8、10、12、14,其中 A
和 B
未发生变化。澄清一下,函数 doublerMutation()
是一个虚拟函数,用于表示一个函数,该函数会导致参数发生变化且无法重写。
我向您推荐一个适用于 C++11 的 C++14 解决方案,并替代 std::index_sequence
和 std::make_index_sequence
。
我建议,对于 applyAsDoubled()
,只需调用一个辅助函数,同时传递 std::index_sequence
数组的数量
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
辅助函数主要基于 std::tuple
,用于打包数组的副本,以及新的 std::array
,用于 C 风格数组副本
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
观察对 getStdArray()
的调用
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
获取单曲 std::array
形式单曲 C 样式数组。
doublerMutation()
还使用了辅助函数
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
以下是一个完整的工作示例
#include <tuple>
#include <array>
#include <iostream>
#include <type_traits>
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
template <typename F, std::size_t ... Is, std::size_t N, typename ... Args>
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
int main ()
{
int A[] = { 1, 2, 3, 4, 5 };
long B[] = { 2, 2, 2, 2, 2 };
auto printSum = [](auto const & ... as)
{
using unused = int[];
typename std::common_type<decltype(as)...>::type sum {};
(void)unused { 0, (sum += as, 0)... };
std::cout << "the sum is " << sum << std::endl;
};
applyAsDoubled(printSum, A, B);
}
如果你也可以使用C++17,使用模板折叠和逗号运算符的强大功能,你可以避免使用unused
s数组,doublerMutation()
可以简化如下
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{ ( doublerMutationH<Is>(tpl), ... ); }
和printSum()
lambda 测试函数如下
auto printSum = [](auto const & ... as)
{ std::cout << "the sum is " << (as + ...) << std::endl; };
可能重复:Is it possible to "store" a template parameter pack without expanding it?
与上述问题类似,我想进一步探讨这个问题并存储一个可变数组。
template<size_t N, typename... Args>
void foo(Args(&...args)[N]) {
Args[N]... args2; // compilation error
}
这有可能实现吗?
最终目标是能够调用 foo()
,改变其可变数组输入的副本,并在突变上执行一些函数。所以,像这样:
template<typename F, size_t N, typename... Args>
void applyAsDoubled(F f, Args(&...args)[N]) {
Args[N]... args2;
doublerMutation(args2...); // doubles each argument; external function, assume it cannot avoid having a side-effect on its parameters
for (int i = 0; i < N; i++)
f(args2[i]...);
}
将被调用并且没有副作用:
int A[N] = { 1, 2, 3, 4, 5 };
int B[N] = { 2, 2, 2, 2, 2 };
applyAsDoubled(printAdded, A, B);
将打印 6、8、10、12、14,其中 A
和 B
未发生变化。澄清一下,函数 doublerMutation()
是一个虚拟函数,用于表示一个函数,该函数会导致参数发生变化且无法重写。
我向您推荐一个适用于 C++11 的 C++14 解决方案,并替代 std::index_sequence
和 std::make_index_sequence
。
我建议,对于 applyAsDoubled()
,只需调用一个辅助函数,同时传递 std::index_sequence
数组的数量
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
辅助函数主要基于 std::tuple
,用于打包数组的副本,以及新的 std::array
,用于 C 风格数组副本
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
观察对 getStdArray()
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
获取单曲 std::array
形式单曲 C 样式数组。
doublerMutation()
还使用了辅助函数
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
以下是一个完整的工作示例
#include <tuple>
#include <array>
#include <iostream>
#include <type_traits>
template <std::size_t I, std::size_t N, typename ... Args>
void doublerMutationH (std::tuple<std::array<Args, N>...> & tpl)
{
for ( auto ui { 0u } ; ui < N ; ++ui )
std::get<I>(tpl)[ui] *= 2;
}
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{
using unused = int[];
(void) unused { 0, (doublerMutationH<Is>(tpl), 0)... };
}
template <typename T, std::size_t N, std::size_t ... Is>
std::array<T, N> getStdArray (T(&a)[N], std::index_sequence<Is...> const &)
{ return { { a[Is]... } }; }
template <typename F, std::size_t ... Is, std::size_t N, typename ... Args>
void applyAsDoubledH (F f, std::index_sequence<Is...> const & is,
Args(&...args)[N])
{
auto isn { std::make_index_sequence<N>{} };
std::tuple<std::array<Args, N>...> tpl { getStdArray(args, isn)... };
doublerMutation(tpl, is);
for (auto ui { 0u } ; ui < N ; ++ui )
f(std::get<Is>(tpl)[ui]...);
}
template <typename F, std::size_t N, typename ... As>
void applyAsDoubled (F f, As(&...as)[N])
{ applyAsDoubledH(f, std::make_index_sequence<sizeof...(As)>{}, as...); }
int main ()
{
int A[] = { 1, 2, 3, 4, 5 };
long B[] = { 2, 2, 2, 2, 2 };
auto printSum = [](auto const & ... as)
{
using unused = int[];
typename std::common_type<decltype(as)...>::type sum {};
(void)unused { 0, (sum += as, 0)... };
std::cout << "the sum is " << sum << std::endl;
};
applyAsDoubled(printSum, A, B);
}
如果你也可以使用C++17,使用模板折叠和逗号运算符的强大功能,你可以避免使用unused
s数组,doublerMutation()
可以简化如下
template <std::size_t N, typename ... Args, std::size_t ... Is>
void doublerMutation (std::tuple<std::array<Args, N>...> & tpl,
std::index_sequence<Is...> const &)
{ ( doublerMutationH<Is>(tpl), ... ); }
和printSum()
lambda 测试函数如下
auto printSum = [](auto const & ... as)
{ std::cout << "the sum is " << (as + ...) << std::endl; };