参数包,捕获子句和初始化器

时间:2016-04-26 19:45:29

标签: c++ lambda c++14 variadic-templates

注意:这个问题是为了好奇。

考虑lambda的文档和parameter pack的文档。

以下代码是合法的:

template<typename... T>
void f(T... t) {
    auto lambda = [t...](){ /* do something */ };
    // do something else
}

同样不言而喻:

void f(int i) {
    auto lambda = [i = i](){ /* do something */ };
    // do something else
}

我想知道是否可以在参数包的capture子句中定义初始值设定项 像这样:

template<typename... Args>
void f(Args&&... args) {
    auto lambda = [params = std::forward<Args>(args)...](){ /* do something */ };
    // do something else
}

好吧,我怀疑它没有意义,但它至少给出了一个想法 有没有可行的解决方案呢?

请不要问我为什么要那样做。我不想那样做。正如我所说,这是为了好奇。

1 个答案:

答案 0 :(得分:4)

不。

你能做的最好的是:

template<typename... Args>
void f(Args&&... args) {
  auto lambda = [params = std::make_tuple(std::forward<Args>(args)...)]()
  { /* do something */ };
  // do something else
}

然后与params进行tuple互动,包括使用get

我发现你最终不得不离开lambda的世界再次打开元素。也许你可以用这样的助手做到这一点:

template<std::size_t...Is, class F>
decltype(auto) unpack_impl( std::index_sequence<Is...>, F&& f ) {
  return std::forward<F>(f)(std::integral_constant<std::size_t, Is>{}...);
}
template<std::size_t N, class F>
decltype(auto) unpack( F&& f ) {
  return unpack_impl( std::make_index_sequence<N>{}, std::forward<F>(f) );
}

采用模板非类型参数N,然后生成一包integral_constants constexpr operator size_t且值0N-1,并传递这些参数通过unpack的lambda。

使用示例:

template<typename... Args>
auto print_later(Args&&... args) {
  auto lambda = [params = std::make_tuple(std::forward<Args>(args)...)](
    auto&& stream
  )
  {
    unpack<sizeof...(Args)>( [&](auto...Is){
      using discard=int[];
      (void)discard{0,(void(
          stream << std::get<Is>( params )
        ),0)...
      };
    });
  };
  return lambda;
}

注意Is传递给内部lambda。基本上这种技术让我们解压缩参数包并在可扩展的上下文中获取它的值,而不必创建新的显式模板函数;相反,我们创建一个可变参数lambda,并使用参数的类型(或对它们的constexpr操作)来获取解包结果。

上面是一个函数,它接受一个参数包,并返回一个接收流并将它们全部打印出来的函数。

live example

unpack函数可以更通用;至少,它需要一个integer_sequence,最后甚至一个变体可以直接采取一堆类型。