たとえば、タプルを構築するための古典的な再帰パターンは、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 番目の選択肢で私の側のエラーを特定できる場合は、そうしてください!