【问题标题】:Variadic typedefs, or "Bimaps done the C++0x way"可变类型定义,或“Bimaps 以 C++0x 方式完成”
【发布时间】:2011-09-16 06:50:30
【问题描述】:

小问题:我可以键入定义可变参数包吗?我需要template <typename ...T> struct Forward { typedef T... args; };


长版:

我正在考虑在 C++0x 中重新实现出色的 boost bimap。回想一下ST 两种类型的bimap 是S xT y 之间关系std::set。对象本身存储在两个独立的内部容器中,我想这些关系跟踪关联的迭代器;这两种类型都可以通过“左”和“右”查找作为键。根据内部容器的选择,值可能是唯一的,也可能不是唯一的,例如如果左容器是一个集合,而右容器是一个多集合,那么一个x 可以映射到许多不同的ys,而右查找给出一个相等的范围。流行的内部容器是setmultisetvectorlist,也许还有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&lt;std::set&lt;int, MyPred&gt;, std::multiset&lt;char, YourPred&gt;&gt; x; 并通过 LeftCont::value_typeRightCont::value_type 提取类型,但我认为如果我可以将键类型作为主要模板参数并允许默认为 std::set 容器。]

【问题讨论】:

    标签: c++11 bimap


    【解决方案1】:

    你可以 typedef 一个元组。但是,我不知道如何将这些类型重新取出。

    最简单的做法是只接受两种完整类型。

    【讨论】:

    • 是的,这很容易,但不知何故不是很优雅。例如,我希望能够提供像 Bimap&lt;int, int&gt; 这样的默认值。在最懒惰的情况下,我只会使用 Boost.Bimap ;-)
    【解决方案2】:

    您可以通过将可变参数包封装在一个元组中,然后使用以下两个帮助模板结构来转发实际可变参数来实现您想要的:

    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 下编译得很好

    【讨论】:

    • 哇,太好了!我没有意识到模板中的其他参数可以有可变参数跟随。非常好!
    猜你喜欢
    • 2011-01-08
    • 1970-01-01
    • 2021-11-11
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    相关资源
    最近更新 更多