2

たとえば、タプルを構築するための古典的な再帰パターンは、1 つの通常のテンプレート パラメーターで機能する必要があるのか​​、それとも 2 つ必要なのか疑問に思います。1 パラメータの場合は次のとおりです。

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

ここで、1 つのテンプレート パラメーターを使用して (直接または再帰で) インスタンス化するとTuple<int>、両方の特殊化が有効であり、宣言があいまいになるはずであると主張できます。ただし、VS2012 Nov CTP はこのコードを受け入れるため、それで問題ないのか、それともコンパイラが適切なだけなのかはわかりません。このケースに言及している標準テキストの文章を見つけることができませんでしたが、それがコンパイルされることは確かに便利であり、「より具体的な」非可変長特殊化が勝つことはある程度論理的です。

これが適切な C++11 でない場合、以下のコードは代替手段であり、2 つの通常のテンプレート パラメーターを使用して、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 呼び出しは、最初の特殊化が 2 つの型で呼び出されたときに、空のパラメーター パックが空であることを認識しません...

したがって、主な質問は依然として次のとおりです。最初のバージョンは有効な C++ ですか?

誰かが 2 番目の選択肢で私の側のエラーを特定できる場合は、そうしてください!

4

2 に答える 2

5

ここで、1 つのテンプレート パラメーターを使用して (直接または再帰で) インスタンス化するとTuple<int>、両方の特殊化が有効であり、宣言があいまいになるはずであると主張できます。

現在の標準によれば、はい、これは確かにあいまいなはずです。この欠陥レポートを参照してください。ただし、委員会は、非可変バリアントが可変バリアントよりもランク付けされると述べており、現在の標準でもそれに依存しています. 例を含む私の別の回答に簡単にリンクします。

現在、基本的にすべての優れたコンパイラは、この DR の解決を既に実装しており、実装しなければstd::common_typeなりません。ええ、ある意味でコンパイラはあなたに親切ですが、それには正当な理由があります。

残念ながら、これは VS2012 Nov CTP ではコンパイルされませんが、これは確かにバグです

はい、これはバグです。November CTP は非常にバグが多いことが知られています。それをいじってみたところ、その夜に 11 個の variadic バグを報告しました (さらに 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 に答える