web-dev-qa-db-ja.com

クラステンプレートをオーバーロードできないのはなぜですか?

読んで この質問 私は疑問に思いました:クラステンプレートのオーバーロードを禁止する技術的な理由はありますか?

オーバーロードとは、たとえば、名前は同じでパラメータが異なる複数のテンプレートがあることを意味します

template <typename T>
struct Foo {};

template <typename T1, typename T2>
struct Foo {};

template <unsigned int N>
struct Foo {};

コンパイラーはオーバーロードされた関数と関数テンプレートを処理することができますが、クラステンプレートに同じ手法(名前マングリングなど)を適用することはできませんか?

最初は、テンプレート識別子だけを取得するとあいまいさの問題が発生する可能性があると思いましたが、これが発生するのはテンプレートテンプレート引数として渡す場合のみであるため、パラメータのタイプを使用して適切なものを選択できます過負荷:

template <template <typename> class T>
void A {};

template <template <unsigned int> class T>
void B {};

A<Foo> a; // resolves to Foo<T>
B<Foo> b; // resolves to Foo<N>

そのような機能が役立つと思いますか?現在のC++ではこれが不可能な「良い」(つまり技術的な)理由はありますか?

45
Luc Touraille

型パラメーター、非型引数、およびテンプレートテンプレートパラメーターを「オーバーロード」することはできませんが、可変個引数テンプレートを特殊化することはできます。

template <typename... T>
struct Foo;

template <typename T1>
struct Foo<T1> {};

template <typename T1, typename T2>
struct Foo<T1,T2> {};
19
log0

これはしばらく前からありましたが、検索したときにまだこの投稿を見つけました。良いスタートを切ってくれた@ log0に感謝します。これは、考えられるすべての列挙に対してテンプレートの特殊化を提供する必要を回避するソリューションです。それは1つの仮定をします:あなたがそれ自身とその基本クラスに関して各テンプレート拡張を定義することができるということです。 (これは以下のFooImplで行われます):

template <typename... T>
struct Foo;

template<typename T>
struct Foo<T> { /* implementation of base class goes here*/};

template <typename C, typename Base>
struct FooImpl : public Base { /* implementation of derived class goes here */};

template<typename C, typename... Bases>
struct Foo<C, Bases...> : FooImpl<C, Foo<Bases...> > { /*NO IMPLEMENTATION HERE */};

FooImplを使用すると、他の方法で発生するあいまいな再帰が解消されます。これにより、次のような宣言が可能になります。

Foo<int> foo_int;
Foo<int, double> foo_int_double;
Foo<int, float, double> foo_int_float_double;

おそらくこれがSTLの現在のやり方ですか?

2
Chris Bowen