可变参数typedef或"Bimap以C ++ 0x方式完成" [英] Variadic typedefs, or "Bimaps done the C++0x way"

查看:111
本文介绍了可变参数typedef或"Bimap以C ++ 0x方式完成"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简短的问题:我可以键入一个可变参量包吗?我需要template <typename ...T> struct Forward { typedef T... args; };.

Short question: Can I typedef a variadic argument pack? I need template <typename ...T> struct Forward { typedef T... args; };.

长版:

我正在考虑重新实现出色的 boost bimap .回想一下,两个类型ST的双图是S xT y之间的关系std::set.对象本身存储在两个独立的内部容器中,并且这些关系跟踪我假设的关联迭代器;两种类型都可以通过向左"和向右"查找作为键.根据内部容器的选择,值可能是唯一的,例如不是.如果左边的容器是一个集合,右边的容器是一个多集合,那么一个x可以映射到许多不同的y,而右边的查找将给出一个相等的范围.流行的内部容器有setmultisetvectorlist,也许还有unordered_*版本.

I was thinking about reimplementing the excellent boost bimap in C++0x. Recall that a bimap of two types S and T is a std::set of relations between S x and T y. The objects themselves are stored in two independent internal containers, and the relations track the associated iterators I suppose; both types can serve as keys via "left" and "right" lookup. Depending on the choice of internal containers, values may be unique or not, e.g. if the left container is a set and the right container is a multiset, then one x can map to many different ys, and right lookup gives an equal-range. Popular internal containers are set, multiset, vector and list, and maybe the unordered_* versions too.

因此,我们需要一个接受两个容器作为模板参数的类型:

So we need a type which accepts two containers as template parameters:

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

但是我们必须接受容器可以接受任意多个参数,因此我们也需要传递所有这些参数.如果我们只需要一组一组可变参量,就没有问题了,因为我们可以直接传递它们.但是现在我们需要两个参数集,所以我想编写一个转发器,像这样使用:

But we must accept that the containers can take arbitrary many arguments, so we need to pass all those, too. If we just needed one set of variadic arguments, it wouldn't be a problem, since we could pass those directly. But now we need two sets of arguments, so I want to write a forwarder, to be used like so:

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! (注释行给出了编译器错误.)

Unfortunately, in the indicated line in Forward I cannot figure out how to typedef the parameter pack! (The commented line gives a compiler error.)

[我想我可以选择一个懒惰的版本Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x;并通过LeftCont::value_typeRightCont::value_type提取类型,但是我认为如果可以将键类型设置为主模板参数并允许它会更好.默认为std::set容器.]

[I suppose I could go for a lazy version Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; and extract the types via LeftCont::value_type and RightCont::value_type, but I thought it'd be nicer if I could make the key types my primary template arguments and allow defaulting to std::set containers.]

推荐答案

您可以通过将可变参量包封装在一个元组中,然后使用以下两个帮助程序模板结构来转发实际可变参量,来实现所需的目标:

You can achieve what you want by encapsulating the variadic argument pack in a tuple and later using the following two helper template structs to forward the actual variadic arguments:

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

您的代码示例如下所示:

your code sample would look like this:

#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下可以正常编译

which compiles just fine under gcc 4.6.0

这篇关于可变参数typedef或"Bimap以C ++ 0x方式完成"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆