Can I use template aliases as template template parameters?
template <template <typename...> class> struct foo {};
template <typename T> using simple_ptr = std::unique_ptr<T>;
foo<std::unique_ptr> a; /开发者_Python百科/ this doesn't work, std::unique_ptr has two parameters
foo<simple_ptr> b; // does this work?
Yes, it is apparently allowed. According to the latest draft of the upcoming standard I could find, it is stated that
A template-argument for a template template-parameter shall be the name of a class template or an alias template [...].
However, alias templates seems very seldomly supported at the moment, so you might have some trouble making it work with most compilers.
People who read the original question may be writing structs that use template template parameters as meta functions, as demonstrated in the listing below.
template <int T>
struct integer
{
using value = T;
};
template <class T, class U, template <class...> class Function>
struct binary_op
{
// Works for add_1, but not add_2
using type = typename Function<T, U>::type;
// Works for add_2, but not add_1
using type = Function<T, U>;
};
template <class T, class U>
struct add_1;
template <int T, int U>
struct add_1<integer<T>, integer<U>>
{
using type = integer<T + U>;
};
template <class T, class U>
using add_2 = typename add_1<T, U>::type;
add_1
and add_2
are both meta-functions, let's distinguish
add_1
as an example of nested typedef-style metafunction (which c++03 supported)add_2
as an example of template alias-style metafunction (which requires c++11)
The binary_op
struct can work either with template alias-style or nested typedef-style metafunctions, but not both. In this answer, I show how such TMP code can be rewritten to avoid this problem.
Suppose that you wish to apply a template template parameter Function
to a parameter pack of values Ts...
. To apply the metafunction, you need either
using type = Function<Ts...>; // template-alias style
or
using type = typename Function<Ts...>::type; // nested typedef style
It would be useful to have another generic metafunction that detects the kind of metafunction that was passed, and applys it accordingly.
The is_alias_metafunction
function, which is implemented below, is a building block for such a facility:
#include <type_traits>
template <class... Ts>
struct sequence;
template <class T>
struct check
{
static constexpr bool value = true;
};
template <
template <class...> class Function,
class S,
class Check = void
>
struct is_alias_metafunction
{
static constexpr bool value = true;
};
template <
template <class...> class Function,
class... Ts
>
struct is_alias_metafunction<
Function,
sequence<Ts...>,
typename std::enable_if<
check<typename Function<Ts...>::type>::value
>::type
>
{
static constexpr bool value = false;
};
Now, we can write a metafunction apply
that applies a template template parameter Function
to the parameter pack Ts...
, regardless of whether Function
is a template alias or a template struct.
template <
bool IsAlias,
template <class...> class Function,
class S
>
struct apply_impl;
template <template <class...> class Function, class... Ts>
struct apply_impl<true, Function, sequence<Ts...>>
{
using type = Function<Ts...>;
};
template <template <class...> class Function, class... Ts>
struct apply_impl<false, Function, sequence<Ts...>>
{
using type = typename Function<Ts...>::type;
};
template <template <class...> class Function, class... Ts>
using apply = typename apply_impl<
is_alias_metafunction<Function, sequence<Ts...>>::value,
Function,
sequence<Ts...>
>::type;
We can now use the apply
metafunction as follows:
using type = apply<Function, Ts...>;
and it will abstract away the difference between 'legacy' metafunctions and modern (c++11) metafunctions.
精彩评论