将参数包扩展到具有折叠表达式的lambda -GCC与Clang

Expanding parameter pack into lambda with fold expression - gcc vs clang

本文关键字:lambda -GCC Clang 表达式 折叠 参数 扩展到      更新时间:2023-10-16

考虑以下代码段:

template <typename TF>
void post(TF){ }
template <typename... TFs>
struct funcs : TFs...
{
    funcs(TFs... fs) : TFs{fs}... { }
    void call() 
    { 
        (post([&]{ static_cast<TFs&>(*this)(); }), ...); 
    }
};

clang 3.8 成功编译了代码。

g 7.0 无法与以下错误进行编译:

prog.cc: In lambda function:
prog.cc:10:43: error: parameter packs not expanded with '...':
        (post([&]{ static_cast<TFs&>(*this)(); }), ...);
                   ~~~~~~~~~~~~~~~~~~~~~~~~^~
prog.cc:10:43: note:         'TFs'
prog.cc: In member function 'void funcs<TFs>::call()':
prog.cc:10:13: error: operand of fold expression has no unexpanded parameter packs
        (post([&]{ static_cast<TFs&>(*this)(); }), ...);
         ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

删除post调用,lambda使G 编译折叠表达式。

是标准以某种方式禁止lambdas,fold表达式和模板函数之间的这种相互作用,还是这是GCC错误?

这是一个旧的GCC错误。这是GCC模板处理要比MSVC差的少数情况之一。羞耻的海湾合作委员会。可耻。

有时有效的解决方法是使用标签和包装扩展。

template<class T>struct tag_t{using type=T; constexpr tag_t(){};};
template<class T>constexpr tag_t<T> tag{};
template<class Tag>using type_t=typename Tag::type;
#define TAG2TYPE(...) type_t<decltype(__VA_ARGS__)>
// takes args...
// returns a function object that takes a function object f
// and invokes f, each time passing it one of the args...
template<class...Args>
auto expand( Args&&...args ) {
  return [&](auto&& f)->decltype(auto) {
    using discard=int[];
    (void)discard{0,(void(
      f( std::forward<Args>(args) )
    ),0)...};
  };
}
template <typename TF>
void post(TF){ }
template <typename... TFs>
struct funcs : TFs...
{
  funcs(TFs... fs) : TFs{fs}... { }
  void call()  { 
    expand( tag<TFs>... )
    ([&](auto tag){
      post(static_cast< TAG2TYPE(tag)& >(*this)());
    });
  }
};

我们每次通过通过Lambda来避免在Lambda的末端进行扩展。相反,我们进行了一组参数,并将其扩展为一组lambda调用。

lambda将类型作为标签传递,然后将其转换回类型。

实例示例

如果您通过了临时性,请勿存储expand的返回类型。

这是一个众所周知的G 错误(#47226),在... 2011年报告。