This is an old gcc bug . This is one of the few cases where handling gcc templates is worse than MSVC. Shame on gcc. Shame.
A workaround that sometimes works is to use tags and expand the package.
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 expansion at the end of the lambda, passing through each lambda. Instead, we take a set of arguments and expand it into a set of lambda calls.
The lambda gets the types passed as a tag, then we convert them back to type.
Living example
Do not save the return type expand
if you passed temporary files to it.
source share