问题
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