Why is it not possible to overload class templates? - c++

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++?

Section 12.5 from Templates the Complete Guide (Amazon) contains this quote:
You may legitimately wonder why only class templates can be partially specialized. The reasons are mostly historical.
It is probably possible to define the same mechanism for function templates (see Chapter 13).
In some ways the
effect of overloading function templates is similar, but there are also some subtle differences. These differences are
mostly related to the fact that the primary template needs to be
looked up when a use is encountered. The specializations are
considered only afterward, to determine which implementation should be
used.
In contrast, all overloaded function templates must be brought
into an overload set by looking them up, and they may come from
different namespaces or classes. This increases the likelihood of
unintentionally overloading a template name somewhat.
Conversely, it
is also imaginable to allow a form of overloading of class templates.
Here is an example:
// invalid overloading of class templates
template<typename T1, typename T2> class Pair;
template<int N1, int N2> class Pair;
However, there doesn't seem to be a pressing need for
such a mechanism.
Furthermore, the Design and Evolution of C++ (Amazon) contains this quote in section 15.10.3
I therefore concluded that we needed a mechanism for "specializing"
templates. This could be done either by accepting general overloading
or by some more specific mechanism. I chose a specific mechanism
because I thought I was primarily addressing irregularities caused by
irregularities in C and because suggestions of overloading invariably
creates a howl of protests. I was trying to be cautious and
conservative; I now consider that a mistake. Specialization as
originally defined was a restricted and anomalous form of overloading
that fitted poorly with the rest of the language.
Bold emphasis mine. I interpret this as saying that function overload resolution is more difficult to implement (and get right by users) than class specialization. So probably no real technical obstacles (similary for function template partial specialization) but an historical accident.

You cannot "overload" type parameter, non-type argument and template template parameter, but you can specialize variadic template:
template <typename... T>
struct Foo;
template <typename T1>
struct Foo<T1> {};
template <typename T1, typename T2>
struct Foo<T1,T2> {};

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

Can we overload template classes in C++, similar to how we overload functions? [duplicate]

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++?
Section 12.5 from Templates the Complete Guide (Amazon) contains this quote:
You may legitimately wonder why only class templates can be partially specialized. The reasons are mostly historical.
It is probably possible to define the same mechanism for function templates (see Chapter 13).
In some ways the
effect of overloading function templates is similar, but there are also some subtle differences. These differences are
mostly related to the fact that the primary template needs to be
looked up when a use is encountered. The specializations are
considered only afterward, to determine which implementation should be
used.
In contrast, all overloaded function templates must be brought
into an overload set by looking them up, and they may come from
different namespaces or classes. This increases the likelihood of
unintentionally overloading a template name somewhat.
Conversely, it
is also imaginable to allow a form of overloading of class templates.
Here is an example:
// invalid overloading of class templates
template<typename T1, typename T2> class Pair;
template<int N1, int N2> class Pair;
However, there doesn't seem to be a pressing need for
such a mechanism.
Furthermore, the Design and Evolution of C++ (Amazon) contains this quote in section 15.10.3
I therefore concluded that we needed a mechanism for "specializing"
templates. This could be done either by accepting general overloading
or by some more specific mechanism. I chose a specific mechanism
because I thought I was primarily addressing irregularities caused by
irregularities in C and because suggestions of overloading invariably
creates a howl of protests. I was trying to be cautious and
conservative; I now consider that a mistake. Specialization as
originally defined was a restricted and anomalous form of overloading
that fitted poorly with the rest of the language.
Bold emphasis mine. I interpret this as saying that function overload resolution is more difficult to implement (and get right by users) than class specialization. So probably no real technical obstacles (similary for function template partial specialization) but an historical accident.
You cannot "overload" type parameter, non-type argument and template template parameter, but you can specialize variadic template:
template <typename... T>
struct Foo;
template <typename T1>
struct Foo<T1> {};
template <typename T1, typename T2>
struct Foo<T1,T2> {};
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?

Questions about class template argument deduction in C++17

I'm trying to make sense of P0091r3 (the "template argument deduction for class templates" paper that has been adopted into the current C++ draft standard, N4606).
I believe I understand how it works in the simplest possible case, where the template-name identifies a single template:
template<class T>
struct S {
S(T);
S(const std::vector<T>&);
};
int main()
{
std::vector<int> v;
auto s = S(v);
}
S identifies the primary template, so we create a fictitious overload set consisting of
template<class T> void Sctor(T);
template<class T> void Sctor(const std::vector<T>&);
and perform overload resolution on the fictitious call
Sctor(v)
to determine that in this case we want to call the fictitious Sctor(const std::vector<T>&) [with T=int]. Which means we end up calling S<int>::S(const std::vector<int>&) and everything works great.
What I don't understand is how this is supposed to work in the presence of partial specializations.
template<class T>
struct S {
S(T);
};
template<class T>
struct S<std::list<T>> {
S(const std::vector<T>&);
};
int main()
{
std::vector<int> v;
auto s = S(v);
}
What we intuitively want here is a call to S<std::list<int>>::S(const std::vector<int>&). Is that what we actually get, though? and where is this specified?
Basically I don't intuitively understand what P0091r3 means by "the class template designated by the template-name": does that mean the primary template, or does it include all partial specializations and explicit full specializations as well?
(I also don't understand how P0091r3's changes to §7.1.6.2p2 don't break code using injected-class-names such as
template<class T>
struct iterator {
iterator& operator++(int) {
iterator result = *this; // injected-class-name or placeholder?
//...
}
};
but that's a different question altogether.)
Are class template deduction and explicit deduction guides supported in any extant version of Clang or GCC (possibly under an -f flag, like -fconcepts is)? If so, I could play around with some of these examples in real life and probably clear up half of my confusion.
This is somewhat skated over by the proposal, but I think the intent is that only constructors of the primary class template are considered. Evidence for this is that the new [class.template.deduction] has:
For each constructor of the class template designated by the template-name, a function template with the following properties is a candidate: [...]
If we're talking about "the" class template, then this is the primary class template, particularly as class template partial specializations are not found by name lookup ([temp.class.spec]/6). This is also how the prototype implementation (see below) appears to behave.
Within the paper, class template partial specializations are contemplated in the section "Pros and cons of implicit deduction guides", but rather out of concern that constructors within the main class template could trigger a hard (non-SFINAE) error:
template<class T> struct X {
using ty = T::type;
static auto foo() { return typename T::type{} };
X(ty); #1
X(decltype(foo())); #2
X(T);
};
template<class T>
struct X<T*> {
X(...);
};
X x{(int *)0};
Your plea for class template partial specialization constructors to be considered is on the face of it reasonable, but note that it could result in ambiguity:
template<class T> struct Y { Y(T*); };
template<class T> struct Y<T*> { Y(T*); };
Y y{(int*) 0};
It would probably be desirable for the implicitly generated deduction guides to be ranked (as a tie-breaker) by specialization of the class template.
If you want to try out a prototype implementation, the authors have published their branch of clang on github: https://github.com/faisalv/clang/tree/clang-ctor-deduction.
Discussion in the paper ("A note on injected class names") indicates that injected-class-names take priority over template names; wording is added to ensure this:
The template-name shall name a class template that is not an injected-class-name.
I would say that the wording of P0091 as it currently stands is under-specified in this regard. It does need to make it clear whether it is just the primary class template or whether it includes the constructors of all specializations.
That being said, I believe that the intent of P0091 is that partial specializations do not participate in argument deduction. The feature is to allow the compiler to decide what a class's template arguments are. However, what selects a partial specialization is what those template arguments actually are. The way to get the S<std::list<T>> specialization is to use a std::list in the template argument list of S.
If you want to cause a specific parameter to use a specific specialization, you should use a deduction guide. That is what they're for, after all.

how to declare properly the template taking function type as a parameter (like a std::function)

I found out that its not trivial to have a neat syntax like in:
std::function<int(float, bool)>
If I declare the function as:
template <class RetType, class... Args>
class function {};
It would be an ordinary syntax to define function's templated types:
function<int,float,bool> f;
But it works with strange trick with partial template specialization
template <class> class function; // #1
template <class RV, class... Args>
class function<RV(Args...)> {} // #2
Why is that?
Why I need to give the template an empty general form with empty type parameter (#1) or otherwise it just won't compile
This is just the way the language was designed. Primary templates can't do complex decomposition of types like that; you need to use partial specialization.
If I understand correctly, you would like to just write the second version without having to supply the primary template. But think about how the template arguments map to the template parameters:
template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}
function<int(float,bool)>; //1
function<int, float, bool>; //2
Option 1 is what you want to write, but note that you pass a single function type to a template where the parameters are a two type parameters and a type parameter pack. In other words, writing this without a primary template means that your template arguments wouldn't necessarily match the template parameters. Option 2 matches the template parameters, but it doesn't match the specialization.
This makes even less sense if you have more than one specialization:
template <class RV, class Arg1, class... Args>
class function<RV(Arg1, Args...)> {}
template <class T, class RV, class Arg1, class... Args>
class function<RV (T::*) (Arg1, Args...)> {}
You could maybe think up some rules to infer the primary template from the specializations, but that seems pretty awful to me.
You have to keep in mind that int (float, bool) is a type. More precisely, it's the type "function which takes two parameters of type float and bool, and returns int."
Since it's a type, it's obvious the template must have one type parameter in the place where you want to use the syntax int (float, bool).
At the same time, having just the function type is unwieldy. Sure, you could do it easily. For example, if all you need to do is some kind of a forwarder:
template <class T>
struct CallForwarder
{
std::function<T> forward(std::function<T> f)
{
std::cout << "Forwarding!\n";
return f;
}
};
However, as soon as you want access to the "components" of the function type, you need a way to introduce identifiers for them. The most natural way to do so is the partial specialisation for function types, just as you did in your question (and just as std::function does).
You can actually do this:
template <typename T>
class X { };
X<int(char)> x;
And inside the definition of X you could create a std::function<T> as you would create a std::function<int(char)>. The problem here is that you cannot (at least easily) access the return type and the type of the parameters of the argument (int and char here).
Using the "trick", you can access these without problem - It "simply" makes your code cleaner.
"Why I need to give the template an empty general form with empty type parameter"
Because, you want explicit type differentiation among the "return type" and the "argument types", with the similar lucidness of syntactic sugar. In C++, no such syntax is available for the first hand version of the template class. You must have to specialize it, to be able to distinguish it.
After reading your Q, I looked at the <functional> header file. Even std::function does the same trick:
// <functional> (header file taken from g++ Ubuntu)
template<typename _Signature>
class function;
// ...
/**
* #brief Primary class template for std::function.
* #ingroup functors
*
* Polymorphic function wrapper.
*/
template<typename _Res, typename... _ArgTypes>
class function<_Res(_ArgTypes...)>
As you see in their comments, they treat the specialized version as the "Primary" class. Hence this trick is coming from the standard header itself!

Syntax of C++ Template Template Parameters

I'm having difficulty understanding the syntax of C++ Template Template parameters. I understand why they are useful, as per the excellent description here, I just find their syntax hard to get to understand. Two examples taken from the above website (there are others):
template <typename T, template <typename> class Cont>
class Stack;
and
template <template <typename,typename> class Cont>
class Wrapper3;
Clearly generalizing such declarations is impossible without some understanding of the rationale behind this syntax. Memorizing is harder and does not seem to be of much help.
Edit:
I realize that my attempt at a question came across like an observation. What I'm asking for is help on how to interprete the Template Template parameter syntax in everyday speak. I can do this with the C++ syntax and the all the other programming languages that I've learned. However I'm having difficulty "explaining" the syntax of C++ Template Template parameters to myself. I've gotten a book, "C++ templates : the complete guide" by David Vandevoorde and Nicolai M. Josuttis, and while its a nice book, it hasn't been of much help to me in understanding this syntax which I'm sure many will agree is at best quirky.
I am not sure what is your question exactly, but here is the explanation for the two examples you gave.
template <typename T, template <typename> class Cont>
class Stack;
Stack is a class template with two template parameters. The first parameter, T can be any type (including built-in types, user-defined types, template instantiations and so on). The second parameter, Cont, must be a class template taking one parameter. The parameter is unnamed because it would not make much sense (the parameter is never bound to anything).
template <template <typename,typename> class Cont>
class Wrapper3;
Wrapper3 is a class template with a single parameter, Cont. Cont must be a class template with two parameters.
The syntax to define a template template parameter is the same as the one to define a class template (template <typename [param1], typename [param2], ...> class Name), so I don't really understand what is your problem.
However, I agree that the syntax can become a bit awkward when you start "nesting" template template parameters:
// class template whose parameter must be a class template whose parameter
// must be a class template
template <template <template <typename> class > class C >
struct Wow {};
Doesn't happen that often, though...
There's nothing so arcane about it. Just take out your template template parameters from the original template:
template <typename> class Cont
Any class template with a single type argument fits, such as
template <typename T>
class A {
public:
A(T t) : t_(t) {}
T get() { return t_; }
private:
T t_;
};
And you would use your original template as
Stack<int, A> s;

Difference of keywords 'typename' and 'class' in templates?

For templates I have seen both declarations:
template < typename T >
template < class T >
What's the difference?
And what exactly do those keywords mean in the following example (taken from the German Wikipedia article about templates)?
template < template < typename, typename > class Container, typename Type >
class Example
{
Container< Type, std::allocator < Type > > baz;
};
typename and class are interchangeable in the basic case of specifying a template:
template<class T>
class Foo
{
};
and
template<typename T>
class Foo
{
};
are equivalent.
Having said that, there are specific cases where there is a difference between typename and class.
The first one is in the case of dependent types. typename is used to declare when you are referencing a nested type that depends on another template parameter, such as the typedef in this example:
template<typename param_t>
class Foo
{
typedef typename param_t::baz sub_t;
};
The second one you actually show in your question, though you might not realize it:
template < template < typename, typename > class Container, typename Type >
When specifying a template template, the class keyword MUST be used as above -- it is not interchangeable with typename in this case (note: since C++17 both keywords are allowed in this case).
You also must use class when explicitly instantiating a template:
template class Foo<int>;
I'm sure that there are other cases that I've missed, but the bottom line is: these two keywords are not equivalent, and these are some common cases where you need to use one or the other.
For naming template parameters, typename and class are equivalent. §14.1.2:
There is no semantic difference
between class and typename in a
template-parameter.
typename however is possible in another context when using templates - to hint at the compiler that you are referring to a dependent type. §14.6.2:
A name used in a template declaration
or definition and that is dependent on
a template-parameter is assumed not to
name a type unless the applicable name
lookup finds a type name or the name
is qualified by the keyword typename.
Example:
typename some_template<T>::some_type
Without typename the compiler can't tell in general whether you are referring to a type or not.
While there is no technical difference, I have seen the two used to denote slightly different things.
For a template that should accept any type as T, including built-ins (such as an array )
template<typename T>
class Foo { ... }
For a template that will only work where T is a real class.
template<class T>
class Foo { ... }
But keep in mind that this is purely a style thing some people use. Not mandated by the standard or enforced by compilers
No difference
Template type parameter Container is itself a template with two type parameters.
There is no difference between using <typename T> OR <class T>; i.e. it is a convention used by C++ programmers. I myself prefer <typename T> as it more clearly describes its use; i.e. defining a template with a specific type.
Note: There is one exception where you do have to use class (and not typename) when declaring a template template parameter:
template <template <typename> class T> class C { }; // valid!
template <template <typename> typename T> class C { }; // invalid!
In most cases, you will not be defining a nested template definition, so either definition will work -- just be consistent in your use.
This piece of snippet is from c++ primer book. Although I am sure this is wrong.
Each type parameter must be preceded by the keyword class or typename:
// error: must precede U with either typename or class
template <typename T, U> T calc(const T&, const U&);
These keywords have the same meaning and can be used interchangeably inside a template parameter list. A template parameter list can use both keywords:
// ok: no distinction between typename and class in a template parameter list
template <typename T, class U> calc (const T&, const U&);
It may seem more intuitive to use the keyword typename rather than class to designate a template type parameter. After all, we can use built-in (nonclass) types as a template type argument. Moreover, typename more clearly indicates that the name that follows is a type name. However, typename was added to C++ after templates were already in widespread use; some programmers continue to use class exclusively