Variadic template aliases as template arguments (part 2)

大城市里の小女人 提交于 2019-12-03 03:17:19

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!