使用折叠表达式扩展带有索引的参数包
Expand parameter pack with index using a fold expression
我有一个带参数包的模板函数。我想将其扩展为对第二个函数的调用 ,同时还提供包中项目的索引 。我可能可以弄清楚如何用递归来做,但我想尝试用折叠表达式来做。
这是我希望参数包展开成的函数
template<typename T>
void addToRecord(Record& rec, int idx, T&& val)
{
// Do some stuff.
}
这就是带参数包的函数
template<typename... ARGS>
void addRecord(ARGS&& ...values)
{
Record rec;
// addToRecord(rec, ??????) How do expand 'values' here addToRecord with index of each item?
}
这可能吗?我意识到这并不重要,但我也试图通过使用折叠表达式来变得更好。
您可以编写一个需要编译时间 integer sequence 以及值
的辅助函数
template<typename... Args, std::size_t... Is>
void addRecord_impl(Record& rec, std::index_sequence<Is...>, Args && ...values)
{
(addToRecord(rec, Is, std::forward<Args>(values)), ...); // Is and values will be expanded in lock step
}
然后像这样调用这个助手
template<typename... Args>
void addRecord(Args && ...values)
{
Record rec;
addRecord_impl(rec,
std::index_sequence_for<Args...>{},
std::forward<Args>(values)...);
}
这是一个demo
除了另一个答案之外,让我提一个不需要辅助函数的更简单的方法:
template<typename... Args>
void addRecord(Args&&... values) {
Record rec;
int i = 0;
(addToRecord(rec, i++, std::forward<Args>(values)), ...);
}
逗号运算符,
guarantees 将按顺序调用所有addToRecord()
:
In a comma expression E1, E2
, the expression E1
is evaluated, its result is discarded, and its side effects are completed before evaluation of the expression E2
begins.
当我需要这样做时,我喜欢内联。
template<std::size_t...Is>
auto indexer_over( std::index_sequence<Is...> ) {
return [](auto&& f)->decltype(auto){
return f( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N, class F>
auto index_upto( F&& f ) {
return indexer_over(std::make_index_sequence<N>{})(std::forward<F>(f));
}
那么您的代码是:
template<typename... ARGS>
void addRecord(ARGS&& ...values)
{
Record rec;
index_upto<sizeof...(ARGS)>( [&](auto...Is) {
( addToRecord(rec, Is), ... );
} );
}
这优于@evg 的解决方案,即 Is
是每次调用 addToRecord
的编译时间常量,如果这很重要的话。
在 c++20 中,您可以在没有助手的情况下获得 Is
值的编译时集合。
[&]<std::size_t...Is>(std::index_sequence<Is...>) {
( addToRecord(rec,Is), ... );
}( std::make_index_sequence<sizeof...(ARGS)>{} );
我有一个带参数包的模板函数。我想将其扩展为对第二个函数的调用 ,同时还提供包中项目的索引 。我可能可以弄清楚如何用递归来做,但我想尝试用折叠表达式来做。
这是我希望参数包展开成的函数
template<typename T>
void addToRecord(Record& rec, int idx, T&& val)
{
// Do some stuff.
}
这就是带参数包的函数
template<typename... ARGS>
void addRecord(ARGS&& ...values)
{
Record rec;
// addToRecord(rec, ??????) How do expand 'values' here addToRecord with index of each item?
}
这可能吗?我意识到这并不重要,但我也试图通过使用折叠表达式来变得更好。
您可以编写一个需要编译时间 integer sequence 以及值
的辅助函数template<typename... Args, std::size_t... Is>
void addRecord_impl(Record& rec, std::index_sequence<Is...>, Args && ...values)
{
(addToRecord(rec, Is, std::forward<Args>(values)), ...); // Is and values will be expanded in lock step
}
然后像这样调用这个助手
template<typename... Args>
void addRecord(Args && ...values)
{
Record rec;
addRecord_impl(rec,
std::index_sequence_for<Args...>{},
std::forward<Args>(values)...);
}
这是一个demo
除了另一个答案之外,让我提一个不需要辅助函数的更简单的方法:
template<typename... Args>
void addRecord(Args&&... values) {
Record rec;
int i = 0;
(addToRecord(rec, i++, std::forward<Args>(values)), ...);
}
逗号运算符,
guarantees 将按顺序调用所有addToRecord()
:
In a comma expression
E1, E2
, the expressionE1
is evaluated, its result is discarded, and its side effects are completed before evaluation of the expressionE2
begins.
当我需要这样做时,我喜欢内联。
template<std::size_t...Is>
auto indexer_over( std::index_sequence<Is...> ) {
return [](auto&& f)->decltype(auto){
return f( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N, class F>
auto index_upto( F&& f ) {
return indexer_over(std::make_index_sequence<N>{})(std::forward<F>(f));
}
那么您的代码是:
template<typename... ARGS>
void addRecord(ARGS&& ...values)
{
Record rec;
index_upto<sizeof...(ARGS)>( [&](auto...Is) {
( addToRecord(rec, Is), ... );
} );
}
这优于@evg 的解决方案,即 Is
是每次调用 addToRecord
的编译时间常量,如果这很重要的话。
在 c++20 中,您可以在没有助手的情况下获得 Is
值的编译时集合。
[&]<std::size_t...Is>(std::index_sequence<Is...>) {
( addToRecord(rec,Is), ... );
}( std::make_index_sequence<sizeof...(ARGS)>{} );