Могу ли я использовать псевдонимы шаблонов в качестве параметров шаблона шаблона?
Ответ 2
Люди, которые читают исходный вопрос, могут писать структуры, которые используют параметры шаблона шаблона в качестве мета-функций, как показано в приведенном ниже списке.
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
как пример вложенного метафайла (который поддерживается С++ 03)
-
add_2
как пример метафайла шаблона псевдонима (для которого требуется С++ 11)
Структура binary_op
может работать либо с шаблонами псевдонимов, либо с вложенными метафайлами в стиле typedef, но не с обоими. В этом ответе я покажу, как такой код TMP можно переписать, чтобы избежать этой проблемы.
Предположим, что вы хотите применить параметр шаблона шаблона Function
к пакету параметров значений Ts...
. Чтобы применить metafunction, вам нужно либо
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;
};
Теперь мы можем написать metafunction apply
, который применяет параметр шаблона шаблона Function
к пакету параметров 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...>;
и он абстрагирует различие между метафорами "наследие" и современными (С++ 11) метафунками.