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

前端 未结 2 742
被撕碎了的回忆
被撕碎了的回忆 2020-12-20 18:58

Considering the following code snippet:

template 
void post(TF){ }

template 
struct funcs : TFs...
{
    funcs(TFs         


        
相关标签:
2条回答
  • 2020-12-20 19:38

    This is a well-known g++ bug (#47226) that was reported in... 2011.

    0 讨论(0)
  • 2020-12-20 19:45

    This is an old gcc bug. It is one of the few cases where gcc's template handling is worse than MSVC. Shame gcc. Shame.

    A workaround that sometimes works is to use tags and pack expansion.

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

    where we carefully avoid expanding over the end of a lambda by passing the lambda in each time. Instead, we take a set of arguments and expand it into a set of lambda calls.

    The lambda gets the types passed in as a tag, then we convert it back to a type.

    Live example

    Do not store return type of expand if you passed it temporaries.

    0 讨论(0)
提交回复
热议问题