Question

Question courte: Puis-je saisir un pack d'arguments variadiques? J'ai besoin de template <typename ...T> struct Forward { typedef T... args; };.


Version longue:

Je pensais réimplémenter l'excellent boost bimap en C ++ 0x. Rappelons qu'une bimap de deux types S et T est un std::set de relations entre S x et T y. Les objets eux-mêmes sont stockés dans deux conteneurs internes indépendants, et les relations suivent les itérateurs associés, je suppose; les deux types peuvent servir de clés via la recherche «gauche» et «droite». Selon le choix des conteneurs internes, les valeurs peuvent être uniques ou non, par ex. si le conteneur de gauche est un ensemble et le conteneur de droite est un multiset, alors un x peut mapper vers de nombreux ys différents, et la recherche à droite donne une plage égale. Les conteneurs internes populaires sont set, multiset, vector et list, et peut-être aussi les versions unordered_*.

Nous avons donc besoin d'un type qui accepte deux conteneurs comme paramètres de modèle:

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

Mais nous devons accepter que les conteneurs peuvent accepter de nombreux arguments arbitraires, nous devons donc les passer tous aussi. Si nous avions juste besoin d'un un ensemble d'arguments variadiques, ce ne serait pas un problème, puisque nous pourrions les passer directement. Mais maintenant, nous avons besoin de deux ensembles d'arguments, donc je veux écrire un transitaire, à utiliser comme ceci:

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

Voici le modèle que j'ai créé:

#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;
}

Malheureusement, dans la ligne indiquée dans Forward, je ne peux pas comprendre comment taper le pack de paramètres! (La ligne commentée donne une erreur de compilation.)

[Je suppose que je pourrais opter pour une version paresseuse Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; et extraire les types via LeftCont::value_type et RightCont::value_type, mais je pensais que ce serait mieux si je pouvais faire des types de clés mes arguments de modèle principaux et permettre par défaut de std::set conteneurs.]

Était-ce utile?

La solution

Vous pouvez réaliser ce que vous voulez en encapsulant le pack d'arguments variadiques dans un tuple et plus tard en utilisant les deux structures de modèle d'aide suivantes pour transmettre les arguments variadiques réels:

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;
};

et

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;
};

votre exemple de code ressemblerait à ceci:

#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;
}

qui compile très bien sous gcc 4.6.0

Autres conseils

Vous pouvez saisir un tuple.Cependant, je ne saurais pas comment récupérer les types à nouveau.

La chose la plus simple à faire serait d'accepter simplement deux types complets.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top