Les personnes qui lisent la question d'origine peut être écrit les structures qui utilisent le modèle de paramètres de modèle en tant que méta-fonctions, comme le montre la liste ci-dessous.
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
et add_2
sont à la fois méta-fonctions, nous allons distinguer
-
add_1
comme un exemple de imbriquée typedef style metafunction (qui c++03 pris en charge)
-
add_2
comme un exemple de modèle d'alias de style metafunction (ce qui nécessite de c++11)
L' binary_op
struct peut fonctionner soit avec le modèle alias de style ou imbriqués typedef style metafunctions, mais pas les deux. Dans cette réponse, je montre comment ces TMP code peut être réécrit afin d'éviter ce problème.
Supposons que vous souhaitez appliquer un modèle paramètre de modèle Function
à un paramètre pack de valeurs Ts...
. Pour appliquer le metafunction, vous avez besoin de
using type = Function<Ts...>; // template-alias style
ou
using type = typename Function<Ts...>::type; // nested typedef style
Il serait utile d'avoir un autre générique metafunction qui détecte le type de metafunction qui a été passé, et applys en conséquence.
L' is_alias_metafunction
de la fonction, qui est mis en œuvre ci-dessous, est un bloc de construction pour une installation de ce type:
#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;
};
Maintenant, nous pouvons écrire une metafunction apply
qui s'applique un modèle de paramètre de modèle Function
pour le paramètre pack Ts...
, indépendamment de si Function
est un modèle d'alias ou d'un modèle de structure.
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;
Nous pouvons maintenant utiliser l' apply
metafunction comme suit:
using type = apply<Function, Ts...>;
et il va abstraire la différence entre "héritage" metafunctions et moderne du c++(c ++ 11) metafunctions.