【问题标题】:Expand parameter pack with index using a fold expression使用折叠表达式展开带索引的参数包
【发布时间】:2021-10-31 10:19:07
【问题描述】:

我有一个带有参数包的模板函数。我想将其扩展为对第二个函数的调用同时还提供包中项目的索引。我可能可以弄清楚如何使用递归,但我想尝试使用折叠表达式。

这是我希望参数包扩展成的功能

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?
}

这可能吗?我意识到这并不重要,但我也在尝试更好地使用折叠表达式。

【问题讨论】:

    标签: c++ c++17 fold-expression parameter-pack


    【解决方案1】:

    当我需要这样做时,我喜欢内联。

    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)>{} );
    

    【讨论】:

      【解决方案2】:

      除了另一个答案,让我提一个不需要辅助函数的更简单的方法:

      template<typename... Args>
      void addRecord(Args&&... values) {
          Record rec;
      
          int i = 0;
          (addToRecord(rec, i++, std::forward<Args>(values)), ...);
      }
      

      逗号操作符,guarantees表示所有addToRecord()s都会被依次调用:

      在逗号表达式E1, E2 中,表达式E1 被求值,其结果被丢弃,其副作用在表达式E2 开始求值之前完成。

      【讨论】:

      • 我不得不承认,这更像是我所希望的。我在使用折叠表达式时遇到的困难与其说是在看到示例后理解发生了什么,不如说是提前意识到我可以用它们做什么。
      • @Joe 我猜你并不孤单。 ;)
      • +1 来自我。 Evg,你有没有机会提供一个链接来显示foo(foo(), bar()) 中总是在bar 之前被调用? @Joe,这不是公认的答案有什么原因吗?
      • @Elliott en.cppreference.com/w/cpp/language/… 逗号运算符表达式的格式为E1, E2。在逗号表达式E1, E2 中,表达式E1 被求值,其结果被丢弃,其副作用在表达式E2 开始求值之前完成。
      • @Evg,完美。谢谢!
      【解决方案3】:

      您可以编写一个需要编译时间的辅助函数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

      【讨论】:

      • 哇。这让我的 C++98 大脑爆炸了。我需要一些时间来消化这个。
      • @Joe Ouch,我已经有一段时间无法使用至少 c++11 了。我很确定在 98 年写作会让我的头爆炸 ;)
      • 哦不,我使用的是 C++17。我只是老了
      • @Joe 哦,我明白你的意思了。是的,语言发生了很大变化。顺便说一句,我没有转发参数有点草率,所以我解决了这个问题。
      猜你喜欢
      • 1970-01-01
      • 2020-09-26
      • 2019-12-25
      • 2022-01-26
      • 2020-11-29
      • 2013-05-31
      • 2017-11-30
      • 1970-01-01
      • 2015-05-04
      相关资源
      最近更新 更多