2

我想知道用于构建元组的经典递归模式是否应该使用一个常规模板参数,或者是否需要两个。这是一个参数的情况:

// Forward declaration of main tuple class template.
template<typename... Ds> class Tuple;

// Tuple class specialization for the general case
template<typename D, typename... Ds> class Tuple<D, Ds...> {
public:

    typedef D HeadType;
    typedef Tuple<Ds...> TailType;

    Tuple() {}

    Tuple(const D& head, const Ds&... ds) : mHead(head), mTail(ds...) {}

    HeadType mHead;
    TailType mTail;
};

// Sentinel one element case
template<typename D> class Tuple<D> {
public:
    typedef D HeadType;

    Tuple() {}
    Tuple(const D& d) : mHead(d) {}

    HeadType mHead;
};

在这里,您可以争辩说,当使用一个模板参数(直接或在递归中)实例化时:Tuple<int>两种特化都是有效的,并且声明应该是模棱两可的。但是,VS2012 Nov CTP 接受此代码,所以我不知道它是否可以,或者编译器是否很好。我无法在标准文本中找到任何提到这种情况的段落,但它编译肯定很方便,并且在某种程度上,“更具体”的非可变特化获胜是合乎逻辑的。

现在,如果这不是正确的 C++11,下面的代码是一个替代方案,使用两个常规模板参数,因此 1 参数案例不能选择一般特化:

// Forward declaration of main tuple class template.
template<typename... Ds> class Tuple;

// Tuple class specialization for the general case
template<typename D, typename D2, typename... Ds> class Tuple<D, D2, Ds...> {
public:

    typedef D HeadType;
    typedef Tuple<D2, Ds...> TailType;

    Tuple() {}

    Tuple(const D& head, const D2& d2, const Ds&... ds) : mHead(head), mTail(d2, ds...) {}

    HeadType mHead;
    TailType mTail;
};

// Sentinel one element case
template<typename D> class Tuple<D> {
public:
    typedef D HeadType;

    Tuple() {}
    Tuple(const D& d) : mHead(d) {}

    HeadType mHead;
};

遗憾的是,这不能在 VS2012 Nov CTP 上编译,但这肯定是一个错误:当第一个特化被两种类型调用时,对 mTail 的 ctor 调用不理解空参数包是空的......

所以主要问题仍然是:第一个版本是有效的 C++ 吗?

如果有人可以在第二种选择中查明我的错误,请这样做!

4

2 回答 2

5

在这里,您可以争辩说,当使用一个模板参数(直接或在递归中)实例化时:Tuple<int>两种特化都是有效的,并且声明应该是模棱两可的。

按照现在的标准,是的,这确实应该是模棱两可的。请参阅此缺陷报告。然而,委员会表示非可变变量的排名要好于可变变量,甚至依赖于当前标准中的这一点。我将方便地链接到我的另一个答案,其中包含一个示例。

现在,基本上所有好的编译器都已经实现了这个 DR 的解析,他们必须这样做,因为否则std::common_type会被简单地破坏(如果定义为指定)。所以,是的,从某种意义上说,编译器对你很好,但这是有充分理由的。

遗憾的是,这不能在 VS2012 Nov CTP 上编译,但这肯定是一个错误

是的,这是一个错误,众所周知,11 月的 CTP非常错误。当我玩弄它时,那天晚上我提交了 11 个可变参数错误(我想还有 3 个 decltype 错误)。

于 2013-02-27T23:46:16.287 回答
0

您是否尝试过专门化空元组版本?我是类型列表的实现,我总是这样做:

template<typename... T> 
struct Tuple;

template<typename HEAD , typename... TAIL>
struct Tuple<HEAD,TAIL...>
{
    using mHead = HEAD;
    using mTail = typename std::enable_if<sizeof...(TAIL) > 0,Tuple<TAIL...>>::type;

    ...
};

template<>
struct Tuple<>
{
    static_assert(false , "Empty tuples are not valid tuples");
};
于 2013-06-09T14:06:53.087 回答