Considering the following code snippet:
template
void post(TF){ }
template
struct funcs : TFs...
{
funcs(TFs
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.
templatestruct tag_t{using type=T; constexpr tag_t(){};};
templateconstexpr tag_t tag{};
templateusing type_t=typename Tag::type;
#define TAG2TYPE(...) type_t
// takes args...
// returns a function object that takes a function object f
// and invokes f, each time passing it one of the args...
template
auto expand( Args&&...args ) {
return [&](auto&& f)->decltype(auto) {
using discard=int[];
(void)discard{0,(void(
f( std::forward(args) )
),0)...};
};
}
template
void post(TF){ }
template
struct funcs : TFs...
{
funcs(TFs... fs) : TFs{fs}... { }
void call() {
expand( tag... )
([&](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.