Pregunta

Pregunta corta: ¿Puedo escribir un paquete de argumentos variádicos? Necesito template <typename ...T> struct Forward { typedef T... args; };.


Versión larga:

Estaba pensando en reimplementar lo excelente impulsar bimap En C ++ 0x. Recuerde que un bimap de dos tipos S y T es un std::set de relaciones Entre S x y T y. Los objetos en sí se almacenan en dos contenedores internos independientes, y las relaciones rastrean a los iteradores asociados, supongo; Ambos tipos pueden servir como claves a través de la búsqueda "izquierda" y "derecha". Dependiendo de la elección de los contenedores internos, los valores pueden ser únicos o no, por ejemplo, si el contenedor izquierdo es un conjunto y el contenedor derecho es un Multiset, entonces uno x puede mapear a muchos diferentes yS, y la búsqueda derecha da un rango de igual rango. Los contenedores internos populares son set, multiset, vector y list, y tal vez el unordered_* versiones también.

Por lo tanto, necesitamos un tipo que acepte dos contenedores como parámetros de plantilla:

class Bimap<S, T, std::set, std::multiset>

Pero debemos aceptar que los contenedores pueden tomar muchos argumentos arbitrarios, por lo que también debemos aprobar todos esos. Si solo necesitábamos una Conjunto de argumentos variádicos, no sería un problema, ya que podríamos pasarlos directamente. Pero ahora necesitamos dos conjuntos de argumentos, por lo que quiero escribir un reenvío, para ser utilizado así:

Bimap<int, int, std::set, std::set, Forward<std::less<int>, MyAllocator>, Forward<std::greater<int>, YourAllocator>> x;

Aquí está la plantilla que se me ocurrió:

#include <set>
#include <cstdint>

template <typename ...Args>
struct Forward
{
  typedef Args... args; // Problem here!!
  static const std::size_t size = sizeof...(Args);
};

template <typename S, typename T,
          template <typename ...SArgs> class SCont,
          template <typename ...TArgs> class TCont,
          typename SForward = Forward<>, typename TForward = Forward<>>
class Bimap
{
  typedef SCont<S, typename SForward::args> left_type;
  typedef TCont<T, typename TForward::args> right_type;

  template <typename LeftIt, typename RightIt> struct Relation; // to be implemented

  typedef Relation<typename left_type::const_iterator, typename right_type::const_iterator> relation_type;

};


int main()
{
  Bimap<int, int, std::set, std::set, Forward<std::less<int>>, Forward<std::greater<int>>> x;
}

Desafortunadamente, en la línea indicada en Forward ¡No puedo entender cómo escribir el paquete de parámetros! (La línea comentada da un error del compilador).

Supongo que podría ir por una versión perezosa Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; y extraer los tipos a través de LeftCont::value_type y RightCont::value_type, pero pensé que sería mejor si pudiera hacer de los tipos clave de mis argumentos de plantilla principal y permitir el valor predeterminado a std::set contenedores.

¿Fue útil?

Solución

Puede lograr lo que desea encapsulando el paquete de argumentos variádicos en una tupla y luego usando las siguientes dos estructuras de plantilla de ayuda para reenviar los argumentos variádicos reales:

template<typename PackR, typename PackL>
struct cat;

template<typename ...R, typename ...L>
struct cat<std::tuple<R...>, std::tuple<L...>>
{
        typedef std::tuple<R..., L...> type;
};

y

template<typename Pack, template<typename ...T> class Receiver>
struct Unpack;

template<typename ...Args, template<typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
        typedef Receiver<Args...> type;
};

Su muestra de código se vería así:

#include <set>
#include <cstdint>
#include <tuple>

template<typename PackR, typename PackL>
struct Cat;

template<typename ...R, typename ...L>
struct Cat<std::tuple<R...>, std::tuple<L...>>
{
        typedef std::tuple<R..., L...> type;
};

template<typename Pack, template<typename ...T> class Receiver>
struct Unpack;

template<typename ...Args, template<typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
        typedef Receiver<Args...> type;
};

template<typename ...Args>
struct Forward
{    
        //typedef Args... args; // Problem here!!
        typedef std::tuple<Args...> args; // Workaround

        static const std::size_t size = sizeof...(Args);
};

template<typename S, typename T, 
        template<typename ...SArgs> class SCont, 
        template<typename ...TArgs> class TCont, 
        typename SForward = Forward<> ,
        typename TForward = Forward<>>
class Bimap
{
        //typedef SCont<S, typename SForward::args> left_type;
        //typedef TCont<T, typename TForward::args> right_type;
        typedef typename Unpack<typename Cat<std::tuple<S>, typename SForward::args>::type, SCont>::type left_type; //Workaround
        typedef typename Unpack<typename Cat<std::tuple<T>, typename TForward::args>::type, TCont>::type right_type; //Workaround

        template<typename LeftIt, typename RightIt> struct Relation; // to be implemented

        typedef Relation<typename left_type::const_iterator, typename right_type::const_iterator> relation_type;

};

int main()
{
    Bimap<int, int, std::set, std::set, Forward<std::less<int>> , Forward<std::greater<int>>> x;
}

que se compila bien bajo GCC 4.6.0

Otros consejos

Puedes escribir una tupla. Sin embargo, no sabría cómo volver a salir los tipos.

Lo más fácil de hacer sería aceptar dos tipos completos.

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