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.
Related
I have a template that inherits from another template, with itself as the second template's template parameter. The inherited template defines a static function:
template<class T> class A
{
public:
static void foo();
};
template<class T> class B : public A<B>
{
};
Now I want to implement the static function for the class A specialized with B, but with B not specialized. But I can't figure out how to declare the template. I'm not even sure if this is possible. My first try was:
template<class T> void A<B<T>>::foo()
{
}
But this gives the error:
"Nested name specifier 'A<B<T>>::" for declaration does not refer into a class, class template or class template partial specialization"
I've tried different things like adding "template<>" in front but none of those worked. I am able to compile this:
template<> void A<B<int>>::foo()
{
}
As well as this:
template<class T> void A<T>::foo()
{
}
Is this an attempt at partial specialization? My first impression is no (there are no templates with multiple parameters where I want to specialize one of them). Rather, I want to specialize a template with another template that is not specialized. Is this possible, and if so what is the proper syntax?
This is indeed partial specialization. You cannot partially specialize just a method, you must partially specialize the whole class. See this answer. You might try implementing foo in a separate helper struct and partially specializing that struct instead.
Here is an example using a helper struct.
#include <iostream>
template<class T> struct t_helper
{
static void foo()
{
std::cout << "Not B<T>\n";
}
};
template<class T> class A
{
public:
static void foo() {
t_helper<T>::foo();
}
};
template<class T> class B {};
// Specialize the behavior of A<T>::foo() for all B types
template<class T>
struct t_helper<B<T>>
{
static void foo()
{
std::cout << "Is B<T>\n";
}
};
int main()
{
A<int>::foo(); // Prints "Not B<T>\n"
A<B<int>>::foo(); // Prints "Is B<T>\n"
return 0;
}
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.
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.
The following gives me a couple compile errors:
error C2995: 'void A<T>::B<Q>::func(void)' : function template has already been defined
error C3855: 'A<T>::B<Q>': template parameter 'Q' is incompatible with the declaration
How can I do this without having the definitions in the class declaration?
template<typename T>
struct A
{
template<typename Q>
struct B
{
void func();
};
};
template<typename T>
template<typename Q>
void A<T>::B<Q>::func()
{
}
template<typename T>
template<>
void A<T>::B<int>::func()
{
}
Edit:
According to 14.7.3 ยง16 a nested class template cannot be specialized if it's enclosing class template is not also specialized. However, that makes me wonder why the nested class specialization works when it's completely defined within the outer class declaration like so:
template<typename T>
struct A
{
template<typename Q>
struct B
{
void func(){}
};
template<>
struct B<int>
{
void func(){}
};
};
Perhaps this is just VS2010 allowing me to do something I shouldn't be able to do?
The problem is in the fact that you need to be able to declare the templated type when you use the class (or struct).
So, if you have a templated nested class, its type would need to be set in the class itself, because you won't be able to do that from the "outside".
for example:
template<typename T>
struct A
{
template<typename Q>
struct B
{
void func(){}
};
};
Now, lets say you'd want to declare a variable of type A<int> with B<int> ... how would you do it ?
A<int>::B<int> a; //this syntactically would mean a is of type B<int>
A<int,int> a; //this would mean A is a templated class with 2 templated types
So, you can't really access B in the declaration.
So, B's type has to be set within the class A.
Nested Class Templates
template <class A,class B>
class H {
public:
A a;
B b;
void fac();
};
template <class B,class A>
void H<B,A>::fac() {
}
What does which follows H exactly mean ?
Since I declared template <class B,class A>, <B,A> seemed to be meaningless....
Can anybody help me ?? Thnx!!
There's no language rule preventing you from doing something like
template<class B> void H<B, B>::fac() {
}
and indeed it may be necessary for any explicit or partial specializations. However, since the vast, vast majority of template code is directly inline, it's really of little consequence.
For example:
template<class A, class B>
class H
{
public:
A a;
B b;
void fac();
};
template<class A> class H<A, A> {
public:
A a, b;
void fac();
};
template<class A, class B> void H<A, B>::fac() {
}
template<class B> void H<B, B>::fac() {
}
Typically, you put the template implementation in the template declaration itself:
template<class A, class B>
class H
{
public:
A a;
B b;
void fac()
{
// Implementation
}
};
However, it is also possible to separate it out:
template<class A, class B>
class H
{
public:
A a;
B b;
void fac();
};
template<class A, class B>
void H<A, B>::fac()
{
// Implementation
}
These two snippets mean the same thing. It's just how the C++ syntax works. Note that the identifier H in the first code snippet doesn't refer to an actual class; it refers to a template class, which is different from a normal class. H is the identifier of a family of classes that are similar but uses different template parameters. That's why you have to say H<A, B> and not just H.
Think about how it usually works for non-template classes:
class NonTemplateH
{
public:
int a;
short b;
void fac();
};
void NonTemplateH::fac()
{
// Implementation
}
You can see how they are similar.
The difference between
template <class A, class B>
void H<A, B>::foo()
and
template <class A, class B>
void H::foo()
is that in the second case foo is a function template inside a non-template class H.
You can only use H without the template arguments at the class scope of H. That part of the definition still belongs to the global scope, where you have to explicitly say what H is.
You asked:
Since I declared template <class B,class A>, <B,A> seemed to be
meaningless....
No, that is not meaningless. To understand that, consider this code:
template <class A,class B>
class H {
template<class C> //note this line!
void fac();
};
Note: Now, fac() is a function template. You've to define it like this:
template <class A,class B> //as usual.
template <class C> //notice this line especially! (not so usual)
void H<A,B>::fac()
{
//your code
}
H<A,B> is needed because it tells the compiler that A and B are template parameters to the class template H, NOT to the function template fac(). C is the tempate parameter to the function template. Notice, I didn't write fac<C>() in the definition. Compiler automacally understands it.
Also, you can interchange the symbol A and B. But if you do this, then do this consistently.