Why is it not possible to overload class templates?

Viewed 12811

Reading this question made me wonder: is there a technical reason for disallowing class templates overloads?

By overloading, I mean having several templates with the same names, but different parameters, for instance

template <typename T>
struct Foo {};

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

template <unsigned int N>
struct Foo {};

The compiler manages to handle overloaded functions and function templates, wouldn't it be possible to apply the same techniques (e.g. name mangling) to class templates?

At first, I thought that perhaps that would cause some ambiguity issues when taking the template identifier alone, but the only time this can happen is when passing it as a template template argument, so the type of the parameter could be used to choose the appropriate overload:

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>

Do you think such feature could be useful? Is there some "good" (i.e. technical) reasons why this is not possible in current C++?

3 Answers

This has been around for a while now, but I still found this post when searching. Thanks to @log0 for providing me with a good start. Here is a solution that avoids needing to provide a template specialisation for all possible enumerations. It does make one assumption: that you can define each template expansion in terms of itself and its base classes. (This would be done in FooImpl below):

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

The use of FooImpl breaks the ambiguous recursion that otherwise results. This then allows declarations such as the following:

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

Perhaps this is how the STL now does it?

Related