Matching template aliases as template template parameters

落花浮王杯 提交于 2019-12-08 07:28:51

问题


I'm currently writting a metafunction to evaluate expressions, something like boost::mpl::apply:

template<typename EXPRESSION , typename... ARGS>
using eval = typename eval_impl<EXPRESSION,ARGS...>::result;

As you can see, I'm using C++11 template aliases to avoid writting typename ::result when using the evaluator.

Among other specializations, eval_impl (The implementation of the evaluation metafunction) has an specializationfor the case the user passes a parametrized expression (Such as a metafunction) and a set of parameters. In other words, for using eval as a high-order metafunction to evaluate a metafunction with a set of specified parameters.

For that case, I have written a specialization as follows:

template<template<typename...> class F , typename... PLACEHOLDERS , typename... ARGS>
struct eval_impl<F<PLACEHOLDERS...>,ARGS...> : public F<ARGS...> {}

Now consider a use case:

template<typename ARG , typename... ARGS> using first_of = ARG;

using call = eval<first_of<_1,_2,_3,_4> , bool,float,char,int>;

Here we define a custom metafunction first_of as a template alias, and we pass it to eval together with a set of parameters to be called (evaluated) with. _1, _2... are just placeholders.

I have expected that eval call instances the specialization defined above, but it doesn't. And if the aliased type is not a type itself, but a one-parameter template, GCC 4.8.1 says:

Error: Expected one template parameter, two provided

At the point of instantation of that eval_impl specialization.

So that errors give me to think that the template alias is not taken in the template template parameter of the partial specialization, the aliased type is matched instead.

As you can see in the examples, thats not what I wan't, I need the template alias to be matched as any other metafunction. Is there any way to achieve that?


回答1:


You are this close! You only need to use a class instead of an alias:

template<typename ARG, typename... ARGS>
struct first_of { using type = ARG; };

See live example.

You cannot use an alias directly because

 first_of<_1,_2,_3,_4>

is immediately substituted for _1, which is not of the form expected by eval_impl.

I don't find this is a limitation because we usually define template functions in the above form, and then define additional aliases like

template<typename ARG, typename... ARGS>
using first_of_t = typename first_of<ARG, ARGS...>::type;

for easier use. So we usually have both; you'll have to use the former with eval.


Attempt 2. Also note that direct use of an alias is possible without placeholders at all:

template<template<typename...> class F, typename... ARGS>
using alias_eval = F<ARGS...>;

in which case you can say

using alias_call = alias_eval<first_of_t, bool, float, char, int>;

as in your first attempt. See updated example. But I guess this is of no use because you intend to use placeholders in a less trivial way.


Attempt 3. Yet another option is to delay substitution of the alias, e.g.

template<template<typename...> class F, typename... PLACEHOLDERS>
struct holder {};

template<typename EXPRESSION, typename... ARGS>
struct holder_eval_impl;

template<template<typename...> class F, typename... PLACEHOLDERS, typename... ARGS>
struct holder_eval_impl<holder<F, PLACEHOLDERS...>, ARGS...> :
    public F<ARGS...> {};

template<typename EXPRESSION, typename... ARGS>
using holder_eval = typename holder_eval_impl<EXPRESSION, ARGS...>::type;

which is very close to your intended syntax

using holder_call =
    holder_eval<holder<first_of,_1,_2,_3,_4>, bool, float, char, int>;

especially if you use a short name for holder. Again, live example.



来源:https://stackoverflow.com/questions/22923628/matching-template-aliases-as-template-template-parameters

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