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.