Variadic typedefs, или "Bimaps сделали C ++ 0x путь" - PullRequest
8 голосов
/ 16 июня 2011

Короткий вопрос: могу ли я печатать пакет с переменными аргументами?Мне нужно template <typename ...T> struct Forward { typedef T... args; };.


Длинная версия:

Я думал о реализации превосходного бимапа буста в C ++ 0x.Напомним, что двунитка двух типов S и T представляет собой std::set из отношений между S x и T y.Сами объекты хранятся в двух независимых внутренних контейнерах, и я полагаю, что отношения отслеживают связанные итераторы;оба типа могут служить ключами при поиске «влево» и «вправо».В зависимости от выбора внутренних контейнеров, значения могут быть уникальными или нет, например, если левый контейнер является множеством, а правый контейнер является мультимножеством, то один x может отображаться на множество различных y с, и правый поиск даетравный диапазон.Популярные внутренние контейнеры: set, multiset, vector и list, а также, возможно, версии unordered_*.

Поэтому нам нужен тип, который принимает два контейнера в качестве параметров шаблона:

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

Но мы должны согласиться с тем, что контейнеры могут принимать произвольно много аргументов, поэтому нам нужно также передать все эти аргументы.Если бы нам просто потребовался один набор переменных аргументов, это не было бы проблемой, поскольку мы могли бы передавать их напрямую.Но теперь нам нужно два набора аргументов, поэтому я хочу написать сервер пересылки, который будет использоваться следующим образом:

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

Вот шаблон, который я придумал:

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

К сожалению, в указанной строке в Forward я не могу понять, как ввести определение пакета параметров!(Закомментированная строка выдает ошибку компилятора.)

[Полагаю, я мог бы пойти на ленивую версию Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; и извлечь типы с помощью LeftCont::value_type и RightCont::value_type, но я подумал, что это будет лучшеесли бы я мог сделать ключи типизировать мои первичные аргументы шаблона и позволить по умолчанию std::set контейнеры.]

Ответы [ 2 ]

9 голосов
/ 16 июня 2011

Вы можете достичь того, чего хотите, путем инкапсуляции пакета переменных аргумента в кортеж, а затем с помощью следующих двух вспомогательных структур шаблона для пересылки фактических аргументов переменной:

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

Ваш пример кода будет выглядеть так:

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

, который прекрасно компилируется под gcc 4.6.0

0 голосов
/ 16 июня 2011

Вы можете ввести определение кортежа.Однако я не знаю, как потом вернуть типы обратно.

Самое простое, что можно сделать, это просто принять два полных типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...