Domanda

Breve domanda: posso digitare un pacchetto di argomenti variadici? Ho bisogno template <typename ...T> struct Forward { typedef T... args; };.


Versione lunga:

Stavo pensando di reimplementare l'eccellente Boost Bimap In C ++ 0x. Ricordiamo che un cronometro di due tipi S e T è un std::set di relazioni fra S x e T y. Gli oggetti stessi sono memorizzati in due contenitori interni indipendenti e le relazioni tracciano gli iteratori associati che suppongo; Entrambi i tipi possono fungere da tasti tramite la ricerca "a sinistra" e "a destra". A seconda della scelta dei contenitori interni, i valori possono essere univoci o meno, ad esempio se il contenitore sinistro è un set e il contenitore destro è un multiset, quindi uno x può mappare a molti diversi yS e la ricerca destra dà un parità di raggio. I container interni popolari lo sono set, multiset, vector e list, e forse il unordered_* anche versioni.

Quindi abbiamo bisogno di un tipo che accetti due contenitori come parametri del modello:

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

Ma dobbiamo accettare che i contenitori possano assumere molti argomenti arbitrari, quindi dobbiamo passare anche tutti. Se avessimo solo bisogno uno Insieme di argomenti variadici, non sarebbe un problema, dal momento che potremmo passare direttamente quelli. Ma ora abbiamo bisogno Due Set di argomenti, quindi voglio scrivere un spedizioniere, da usare in questo modo:

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

Ecco il modello che mi è venuto in mente:

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

Sfortunatamente, nella linea indicata in Forward Non riesco a capire come digitare il pacchetto dei parametri! (La riga commentata fornisce un errore del compilatore.)

Suppongo che potrei scegliere una versione pigra Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; ed estrarre i tipi tramite LeftCont::value_type e RightCont::value_type, ma ho pensato che sarebbe stato più bello se potessi fare i tipi chiave i miei argomenti del modello principale e consentire il inadempienza a std::set contenitori.

È stato utile?

Soluzione

Puoi ottenere ciò che desideri incapsulando il pacchetto di argomenti variadici in una tupla e successivamente usando le seguenti strutture del modello di helper per inoltrare gli argomenti variadici effettivi:

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

e

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

Il tuo esempio di codice sembrerebbe così:

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

che compila bene sotto GCC 4.6.0

Altri suggerimenti

Puoi digitare una tupla. Tuttavia, non saprei come riportare indietro i tipi.

La cosa più semplice da fare sarebbe accettare solo due tipi completi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top