Is it possible to overload a template class? - c++

I found that template method could be overloaded, can I do the same on template classes? If 2 template classes match a template class instantiation, we can use the parameter type in the constructor to deduce which one to use.
template <typename T>
class A{
A(T){}
};
template <typename T>
class A{
A(T*){}
};
int main(){
A<int*> a((int*)0);
A<int> a((int*)0);
return 0;
}

No. This is not allowed. Instead class template can be specialized (including partial specialization). This pretty much achieves the effect of overloading (which is only for functions)
Note that template parameters can not be deduced from constructor arguments.
template<class T> struct X{
void f(){}
};
template<class T> struct X<T*>{
void f(){}
};
int main(){
X<int> x;
x.f(); // calls X<T>::f
X<int *> xs;
xs.f(); // calls X<T*>::f
}

Related

Constrain member function template in class template with inner type same as class template type

I want a member function that more or less does the same thing as this:
template<class T, template<class T> class U>
void f(const U<T>& x)
{
...
}
...but in a template class already parameterized on T:
template<class T>
class A
{
???
// maybe template< template<class T> class U>
// maybe template< class U<T> >
void f(const U<T>& x)
{
...
}
}
This might be doable using type aliases (with using), but this is an older C++98 codebase, so I can't try that route.
You can simply use T inside the member function template when deducing the argument:
template<class T>
struct A
{
template<template<class> class U>
void f(const U<T> & x) {}
};
This constrains the function template f to only accept arguments that are instantiations of a class on T.
A<int> a;
S<int> s1;
a.f(s1); // ok, a and s1 are instantiated over int
a.f(42); // error, 42 is not a U<T>
S<double> s2;
a.f(s2); // error, a is instantiated over int,
// but s2 is instantiated over double
Here's a demo.

C++ template argument deduction/substition failed

I'm using a template library in which class B is a templated class parametrized by class A. I have a declaration
template <class A, template <class A> class B>
void foo(){
B<A> x;
}
later on I want to invoke this as
foo<A, B>();
where X is a concrete class in the library and Y is a particular templated concrete class in the library. However, I get the titled error abour template argument deduction/substitution failed. If I change the declaration of foo to remove the templates and subsitute in X and Y, then it all works ok. I also tried
foo<X, Y<X> >();
which failed with the same message. Can someone explain why this is happening?
I'm using gcc 5.3.0
Here's a complete example which gives the indicated behavior
#include <vector>
template <class A, template <class A> class B>
void foo() {
B<A> x;
}
void bar() {
foo<int, std::vector>();
}
You have two issues that I can see.
First is that std::vector takes more than one template argument so the template template parameter template<class A> class B will never match std::vector.
Second and slightly less of an issue is that the class A here template<class A> class B shadows the previous class A here template <class A/*here*/, template <class A> class B>
To fix both of these issues you can declare the second template argument as an nameless variadic template like so: template <class...> class B.
Combining everything you get:
#include <vector>
template <class A, template <class...> class B>
void foo() {
B<A> x;
}
void bar() {
foo<int, std::vector>();
}
Edit:
If you would like to only use B in the form of B<A> you could do one of a few things:
template <class A, template <class...> class B>
void foo() {
using C = B<A>;
C x;
}
OR:
template <class A, template <class...> class B, class C = B<A>>
void foo() {
C x;
}
OR (depending on the larger point of your code) you could just accept the whole thing as one template parameter:
template <class A>
void foo() {
A x;
}
void bar() {
foo<std::vector<int>>();
}
std::vector is not templated on one class, so it does not match your type. You can coerce it to match by
template <class X> using MyVector = std::vector<X>;
and that will work. C++17 will just plain fix this to work as you expected it to.

partial template member specialization

Given the following definitions:
template <typename T>
class A {
public:
void f();
};
template <typename T>
void
A<T>::f()
{}
template <typename T>
class B {};
How would I partially specialize A<B<T>>::f, i.e. f for some B<T>? I'm basically looking for the right magic to substitute the ??? below
template <???>
void
A<B<T>>::f()
{}
You can have an explicit specialization, from [temp.expl.spec]:
An explicit specialization of any of the following:
โ€” ...
โ€” member function of a class template
โ€” ...
can be declared by a declaration introduced by template<>
That is:
template <>
void A<B<int>>::f() {
std::cout << "B\n";
}
But you cannot have a partial specialization of a member function of a class template. You would have to partially specialize the entire class:
template <typename T>
class A<B<T>> {
public:
void f() {
std::cout << "B\n";
}
// ... all other members you want in A<B<T>> ...
};
You cannot partially specialize a member function (nor in fact any function). You need to partially specialize the whole class:
template<typename T>
class A<B<T>>
{
// implement member functions for this specialization here
};
If you must have:
template <typename T>
void A<B<typename T>>::f() {}
then your only choice is to partially specialize A.
template <typename T> class A<B<T>>
{
public:
void f();
};
C++11 has Alias Templates, allowing you do do something like:
template<T>
using AB = A<B<T>>;
Then you can refer to AB<T> instead of A<B<T>>.
Unfortunately, you can't use that for specialization..
So seems to me the answer to your question is: You can't do that, but it's a shame.

Explicit template specialization issue

template <class T>
class Test
{
public:
template<class U> void f(); //generic function
template<> void f<char>(); //Specialization for char.
};
template <class T>
template<class U>
void Test<T>::f() //Definition of generic function
{
}
template<>
template<> void Test<char>::f<char>(){} //Definition of specialization.
int main()
{
Test<char> ob1;
ob1.f<char>(); //Works fine.
Test<int> ob2;
ob2.f<char>(); //Produces linker error.
}
Linker error is
error LNK2019: unresolved external symbol "public: void __thiscall
Test<int>::f<char>(void)"
My requirement is: I should be able to pass any type to Test class and any type to function f(). I should be able to use all combinations of types like below.
Test f()
--------------
int char
char int
int int
I can solve the error by defining another function like below.
template<>
template<> void Test<int>::f<char>(){}
But then what is the use of making Test class as Template ? How to make it work for all combinations ?
C++03, ยง14.7.3/2:
An explicit specialization shall be declared in the namespace of which the
template is a member, or, for member templates, in the namespace of which
the enclosing class or enclosing class template is a member.
An explicit specialization of a member function, member class or static data
member of a class template shall be declared in the namespace of which the
class template is a member.
Therefore you should declare your specialization outside of a class, for example:
template <class T>
class Test
{
public:
template<class U> void f(); //generic function
};
template <class T>
template <class U>
void Test<T>::f() {} //Definition of generic function
template<>
template<>
void Test<char>::f<char>(){} //Specialization.
int main()
{
Test<char> ob1;
ob1.f<char>();
Test<int> ob2;
ob2.f<char>();
}
The problem that you are facing is that you have declared the specialization of f for char in the Test template, and that is incorrect. The compiler is not detecting the error, but it is getting confused and interpreting that you want to provide the specialization of f for char in all template instantiations:
template <typename T>
struct Test {
template <typename U> void f();
template <> void f<char>(); // <- Incorrect
};
When you write Test<int> the compiler instantiates the template and is (mistakenly) accepting it and interepreting that there is an specialization of f for char in Test<int>.
Just remove the line, and you will get the code to compile. It will use the specialization only for Test<char>::f<char>(), and I am not sure whether that is what you want.
If your intention is specializing f for char with all instantiating types, that is not allowed. When you define a template specialization, all enclosing templates be specialized. A common work around is not providing an specialization but a different overload of the member function:
template <typename T>
struct Test {
template <typename U> void f( U );
void f( char );
};
But that won't help you much there, as you cannot provide different overloads for the same arguments (in your case no arguments). Also, in your case you must explicitly call the template to differentiate, and code that explicitly requests the template would not pick up the overload:
int main() {
Test<int> t;
t.f<char>(); // will call template, not "void f(char)"!!
}
Without more details on what you really want to achieve I cannot think on other potential solution to the issue.
My requirement is: I should be able to pass any type to Test class and any type to function f(). I should be able to use all combinations of types like below.
Why do you need an explicit specialization? Why do you unnecessarily want to make your code complex?
The following works for all combinations that you have listed.
template <class T>
class Test
{
public:
template<class U> void f();
};
template <class T>
template<class U>
void Test<T>::f(){}
int main()
{
Test<char> ob1;
ob1.f<char>(); //Works fine. T = char, U = char
Test<int> ob2;
ob2.f<char>(); //Works fine T = int, U = char
}

C++ partial method specialization

Is there a partial specialization for template class method?
template <class A, class B>
class C
{
void foo();
}
it doesn't work to specialize it like this:
template <class A> void C<A, CObject>::foo() {};
Any help?
If you are already have specialized class you could give different implementation of foo in specialized class:
template<typename A, typename B>
class C
{
public:
void foo() { cout << "default" << endl; };
};
template<typename A>
class C<A, CObject>
{
public:
void foo() { cout << "CObject" << endl; };
};
To specialize member function in Visual C++ 2008 you could make it template too:
template<typename A, typename B>
class C
{
template<typename T>
void foo();
template<>
void foo<CObject>();
};
The solution above seems to will be available only in future C++ Standard (according to draft n2914 14.6.5.3/2).
I think there is a misunderstanding there.
There are two kinds of templates:
the template classes
the template methods
In your example, you have a template class, which of course contains some methods. In this case, you will have to specialize the class.
template <class A>
class C<A,CObject>
{
void foo() { ... } // specialized code
};
The problem in your example is relatively simple: you define the method foo for the specialization C but this specialization has never been declared beforehand.
The problem here is that you have to fully specialize your C class (and thus copying a lot of data). There are a number of workarounds.
Inheritance (Composition ?): do all the common work in a base class, then have the C class inherits and specialize as appropriate
Friend: instead of having the 'foo' method being a member of C, define it as a friend free functions and specialize only this method
Delegation: have your 'foo' method call another method 'bar', which is a free function, and specialize 'bar' appropriately
Which in code gives:
// 1- Inheritance
template <class A, class B>
class CBase
{
// Everything that does not require specialization
};
template <class A, class B>
class C: public CBase<A,B>
// depending on your need, consider using another inheritance
// or even better, composition
{
void foo(); // generic
};
template <class A>
class C<A,CObject> : public CBase<A,CObject>
{
void foo(); // specialized
};
// 2- Friend
// note the change in signature:
// - now you need to pass the attributes to be changed
// - the last parameter helps differentiating the overload
// as there is no specialization for functions
template <class A, class B> void foo(Arg1&, Arg2&, const B&);
template <class A> void foo(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
friend template <class, class> foo;
};
// 3- Delegation
// same signature as foo in (2)
template <class A, class B> void bar(Arg1&, Arg2&, const B&);
template <class A> void bar(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
void foo() { bar(member1, member2, B()); }
};
Hope it clarifies, and helps!
No, there is no partial function template specialization in C++0x to be added.
As correctly mentioned above, with regards to function templates basically 2 things were done:
default template arguments were made available;
variadic templates were introduced.
So as before, workarounds should be used to "emulate" partial function templates specialization.
Since the class is the template, you need to specialize that:
template <class A>
class C<A, CObject>
{
void foo() { ... }
}
If I remember correctly, you cannot make partial template specialization for functions. Not sure whether it is included in C++0X
Update:
(Awaiting confirmation) As noted in the comments, partial template specialization of functions is possible in C++0X.
A method template may delegate to (static) methods of partially specialized classes or structs. Template parameters in the outer class are not helpful for answering the question.
class ClassWithSpecializedMethodEmulation
{
private:
template <typename A, typename B> struct Calculator;
public:
template <typename A, typename B> A evaluate(A a, B b)
{
return Calculator<A,B>::evaluate(a,b);
}
private:
template <typename A, typename B> struct Calculator
{
// Common case: multiply
static A evaluate(A a, B b)
{
return (A)(a*b);
}
};
// with double argument a do something else
template <typename B> struct Calculator<double, B>
{
static double evaluate(double a, B b)
{
return (double)(a - b);
}
};
};
In case the method requires access to class members, struct Calculator additionally must be friend of ClassWithSpecializedMethodEmulation and get a this-pointer passed.