2011-06-16 80 views
8

簡短的問題:我可以typedef一個可變參數包嗎?我需要template <typename ...T> struct Forward { typedef T... args; };Variadic typedefs或「Bimaps done the C++ 0x way」


龍版本:

我在想重新實現C++ 0x中的出色boost bimap。回想一下,ST兩種類型的bimap是和T y之間的關係std::set。這些對象本身存儲在兩個獨立的內部容器中,並且這些關係跟蹤我想要的關聯迭代器;這兩種類型都可以通過「左」和「右」查找作爲鍵。取決於內部容器的選擇,值可能是唯一的或不是,例如,如果左邊的容器是一個集合,而右邊的容器是一個多層集合,那麼一個x可以映射到許多不同的y,右邊的查找會給出一個等值範圍。流行的內部容器是set,multiset,vectorlist,也可能是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指定的行我無法弄清楚如何typedef參數包! (註釋的行給出一個編譯錯誤。)

[我想我可以去一個懶惰的版本Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x;並通過LeftCont::value_typeRightCont::value_type提取的類型,但我想那會更好,如果我能做出的密鑰類型我主模板參數並允許默認爲std::set容器。]

回答

9

你可以達到你想要的東西在一個元組封裝一個可變參數包,後來用以下兩個輔助模板結構轉發實際的可變參數:

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

wh我在gcc 4.6下編譯得很好。0

+1

哇,非常棒!我沒有意識到你可以通過模板中的其他參數追蹤可變參數。非常好! – 2011-06-16 15:56:36

0

您可以鍵入一個元組。但是,我不知道如何將這些類型再次取出。

最簡單的事情就是接受兩種完整的類型。

+0

是的,這很容易,但不是很優雅。例如,我希望能夠給出默認值,比如'Bimap '。在最懶的情況下,我只是使用Boost.Bimap ;-) – 2011-06-16 11:19:23

+0

您可以使用decltype將它們取出http://en.wikipedia.org/wiki/Decltype – mikelikespie 2011-10-05 21:33:29