Pregunta

Estaba escribiendo algún código donde tengo una clase que puede aceptar mixins como parámetros de plantilla variádica. Sin embargo, también necesito las Mixins para poder acceder a la clase base a través del idioma CRTP. Aquí hay un ejemplo mínimo que no puede hacer lo que quiero:

template <template <class> class... Mixins>
class Foo : Mixins<Foo<Mixins...>>... {};

Sin embargo, una mezcla a la que podría pasar Foo En general, tendrá varios parámetros de plantilla, como así:

template <class Derived, class Type1, class Type2>
class Bar
{
    Derived& operator()()
    {
        return static_cast<Derived&>(*this);
    }
};

¿Cómo puedo cambiar? Foo ¿Para que pueda hacer que herede de varias clases base, donde controlo los parámetros de plantilla aceptados por cada clase base? Si le digo Foo Una lista de parámetros de plantilla de plantilla, junto con una lista de argumentos para transmitirles, entonces no veo cómo podría asociar cada parámetro de plantilla de plantilla con sus argumentos. Hasta ahora, pensé en algo como esto, pero no sé cómo procedería.

template <template <class...> class T,
    template <class...> class... Ts>
class Foo : /* How do I retrieve the arguments? */
¿Fue útil?

Solución

No estoy muy seguro de haber entendido el problema, así que déjame reformularlo para que podamos comenzar con el pie derecho.

Debe enhebrar el tipo derivado en las clases base, en un caso de uso típico de CRTP, al tiempo que pasa otro parámetro de plantilla a las diversas clases base.

Es decir, una clase base típica será:

template <typename Derived, typename X, typename Y>
struct SomeBase {
};

Y quieres crear tu tipo para que puedas controlar el X y Y y al mismo tiempo pasar el completo Derived clase.


Creo que usaría el apply truco para generar la clase base sobre la marcha, desde un adaptador proporcionado en la lista de argumentos de la Derived clase.

template <typename Derived, typename X, typename Y>
struct SomeBase {};

template <typename X, typename Y>
struct SomeBaseFactory {
  template <typename Derived>
  struct apply { typedef SomeBase<Derived, X, Y> type; };
};

// Generic application
template <typename Fac, typename Derived>
struct apply {
  typedef typename Fac::template apply<Derived>::type type;
};

Entonces, crearías el tipo como:

typedef MyFoo< SomeBaseFactory<int, float> > SuperFoo;

Dónde Foo Se define como:

template <typename... Args>
struct Foo: apply<Args, Foo<Args...>>::type... {
};

Y solo porque ha pasado un tiempo desde que caminé tan profundamente en las plantillas, Revisé que funcionó.


Por supuesto, el Factory en sí mismo no es realmente específico para un tipo dado, por lo que podemos reutilizar el enfoque de envoltura que había experimentado:

template <template <typename...> class M, typename... Args>
struct Factory {
  template <typename Derived>
  struct apply { typedef M<Derived, Args...> type; };
};

Y si, También funciona.

Otros consejos

Si entiendo correctamente su pregunta, debe crear alias de plantilla que reduzcan cada mezcla a un solo parámetro de plantilla.

template <typename Derived>
using BarIntFloat = Bar<Derived, Int, Float>;

template <typename Derived>
using BazQux = Baz<Derived, Qux>;

typedef Foo<BarIntFloat, BazQux> MyFoo;

Aquí hay una solución que se me ocurrió. Puede haber una forma más elegante de hacer esto, pero no podría pensar en ninguna. Una advertencia es que todas las mezclas utilizadas primero deben anidarse en el wrapper estructura, junto con sus respectivos argumentos.

template <template <class...> class Mixin, class... Args>
struct wrapper
{
        typedef Mixin<Args...> type;
};

template <class... Args>
struct test
{

};

template <class Arg, class... Args>
struct test<Arg, Args...> : Arg::type, test<Args...>
{

};

template <class T>
class mixin1 {};

template <class T1, class T2>
class mixin2 {};

template <class T1, class T2, class T3>
class mixin3 {};

int main()
{
        test<wrapper<mixin1, int>, wrapper<mixin2, int, float>> foo;
        return 0;
}

@void-pointer

Esta es la omisión básica de plantillas variádicas. El usuario no puede obtener el tipo I-th de t ... o obtener el valor de los valores ...

Aquí está un enlace De ir con una conferencia nativa de 2012 de Andrei Alexandrescu:

template <typename... Ts>
void fun(const Ts&... vs) {}

• TS no es un tipo; ¡VS no es un valor!

typedef Ts MyList; // error!
Ts var; // error!
auto copy = vs; // error!

Entonces TS/VS debería ser algún tipo de tupla.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top