元の質問を読んだ人は、以下のリストに示すように、テンプレート テンプレート パラメータをメタ関数として使用する構造体を書いている可能性があります。
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
とadd_2
は両方ともメタ関数です。区別しましょう
add_1
ネストされた typedef スタイルのメタ関数 (c++03 がサポート)の例として
add_2
テンプレート エイリアス スタイルのメタ関数の例として(これには c++11 が必要です)
binary_op
構造体は、テンプレート エイリアス スタイルまたは入れ子になった typedef スタイルのメタ関数のいずれかで機能しますが、両方では機能しません。この回答では、このような TMP コードを書き直してこの問題を回避する方法を示します。
テンプレート テンプレート パラメータFunction
を値のパラメータ パックに適用するとしますTs...
。メタ関数を適用するには、次のいずれかが必要です
using type = Function<Ts...>; // template-alias style
また
using type = typename Function<Ts...>::type; // nested typedef style
渡されたメタ関数の種類を検出し、それに応じて適用する別の汎用メタ関数があると便利です。
is_alias_metafunction
以下に実装されている関数は、そのような機能の構成要素です。
#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;
};
これで、テンプレート エイリアスまたはテンプレート構造体に関係なくapply
、テンプレート テンプレート パラメーターFunction
をパラメーター packに適用するメタ関数を作成できます。Ts...
Function
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;
apply
次のようにメタ関数を使用できるようになりました。
using type = apply<Function, Ts...>;
また、「レガシー」メタ関数と最新の (c++11) メタ関数の違いを抽象化します。