This is a follow-up of another question. It refers to the same problem (I hope) but uses an entirely different example to illustrate it. The reason is that in the previous examp
This does not answer the question whether the code above is valid, but is a quite pretty workaround that I have found by experimenting shortly after asking the question, and I think is useful to share.
All that is needed are the following definitions:
template <template <typename...> class F>
struct temp { };
template <typename... A, template <typename...> class F>
F <A...> subs_fun(temp <F>);
template <template <typename...> class F, typename... A>
using subs = decltype(subs_fun <A...>(temp <F>()));
then, wherever F <A...>
would be problematic, replace it with subs <F, A...>
. That's it. I cannot explain why, but it has worked in all cases so far.
For instance, in the SFINAE example of the question, just replace line
template <typename... A> static pass <F <A...> > _(int);
by
template <typename... A> static pass <subs <F, A...> > _(int);
This is a change at one point only, all remaining code stays the same. You don't need to redefine or wrap every template metafunction that with be used as F
. Here's a live example.
If F <A...>
is indeed valid and compilers support it eventually, it is again easy to switch back because changes are minimal.
I find this important because it allows specifying a SFINAE test in just two lines
template <typename T> using type_of = typename T::type;
template <typename T> using has_type = sfinae <type_of, T>;
and is completely generic. Typically, each such test needs at least 10 lines of code and implementations of <type_traits>
are full of such code. In some cases such code blocks are defined as macros. With this solution, templates can do the job and macros are not needed.
I think the situation is pretty well standardized; C++11 14.3.3/1 says:
A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.