使用折叠表达式扩展带有索引的参数包

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 的编译时间常量,如果这很重要的话。

中,您可以在没有助手的情况下获得 Is 值的编译时集合。

[&]<std::size_t...Is>(std::index_sequence<Is...>) {
  ( addToRecord(rec,Is), ... );
}( std::make_index_sequence<sizeof...(ARGS)>{} );