c++ - ¿Puedo usar alias de plantilla como parámetros de plantilla de plantilla?
c++ using (2)
¿Puedo usar alias de plantilla como parámetros de plantilla de plantilla?
template <template <typename...> class> struct foo {};
template <typename T> using simple_ptr = std::unique_ptr<T>;
foo<std::unique_ptr> a; // this doesn''t work, std::unique_ptr has two parameters
foo<simple_ptr> b; // does this work?
Las personas que leen la pregunta original pueden estar escribiendo estructuras que usan parámetros de plantilla de plantilla como metafunciones , como se demuestra en el siguiente listado.
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
y add_2
son ambas meta-funciones , vamos a distinguir
-
add_1
como un ejemplo de metafunción tipo typedef anidada (compatible con c ++ 03) -
add_2
como un ejemplo de metafunción de estilo de alias de plantilla (que requiere c ++ 11)
La estructura binary_op
puede funcionar con estilo de alias de plantilla o con metafunciones de tipo typedef anidadas , pero no con ambas. En esta respuesta, muestro cómo se puede reescribir ese código TMP para evitar este problema.
Suponga que desea aplicar un parámetro de plantilla de plantilla a un paquete de parámetros de parámetros Ts...
Para aplicar la metafunción, necesita cualquiera
using type = Function<Ts...>; // template-alias style
o
using type = typename Function<Ts...>::type; // nested typedef style
Sería útil disponer de otra metafunción genérica que detecte el tipo de metafunción que se aprobó y la aplique en consecuencia.
La función is_alias_metafunction
, que se implementa a continuación, es un bloque de construcción para dicha instalación:
#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;
};
Ahora, podemos escribir una apply
metafunción que aplique un parámetro de plantilla de plantilla al paquete de parámetros Ts...
, independientemente de si Function
es un alias de plantilla o una estructura de plantilla.
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;
Ahora podemos usar la metafunción de apply
siguiente manera:
using type = apply<Function, Ts...>;
y abstraerá la diferencia entre las metafunciones ''heredadas'' y las metafunciones modernas (c ++ 11).
Sí, aparentemente está permitido. De acuerdo con el último borrador del próximo estándar que pude encontrar, se afirma que
Una plantilla-argumento para una plantilla plantilla-parámetro será el nombre de una plantilla de clase o una plantilla de alias [...].
Sin embargo, las plantillas de alias casi nunca se admiten en este momento, por lo que es posible que tenga problemas para hacerlo funcionar con la mayoría de los compiladores.