Understanding (simple?) C++ Partial Template Specialization
Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:
template<typename T, typename U> void f() {} //okay - primary template
template<typename T> void f<T,int>() {} //error - partial specialization
template<> void f<unsigned char,int>() {} //okay - full specialization
But you can partially specialize the class template itself. You can do something like this:
template <class A>
class Thing<A,int> //partial specialization of the class template
{
//..
int doSomething();
};
template <class A>
int Thing<A,int>::doSomething() { /* do whatever you want to do here */ }
Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), must match the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:
template <class A>
int Thing<A,double>::doSomething(); //error
Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,
The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.[...]
For more on this, read my answer here:
C++ - Overload templated class method with a partial specilization of that method
So what is the solution? Would you partially specialize your class along with all the repetitive work?
A simple solution would be work delegation, instead of partially specializing the class template. Write a stand-alone function template and specialize this as:
template <class B>
B doTheActualSomething(B & b) { return b; }
template <>
int doTheActualSomething<int>(int & b) { return b + 1; }
And then call this function template from doSomething()
member function as:
template <class A, class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }
Since in your particular case, doTheActualSomething
needs to know the value of only one member, namely b_
, the above solution is fine, as you can pass the value to the function as argument whose type is the template type argument B
, and specialization for int
is possible being it full-specialization.
But imagine if it needs to access multiple members, type of each depends on the template type argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one type argument to the function template, and you cannot partially specialize the function for just, say, one type (as its not allowed).
So in this case you can define a class template instead, which defines a static non-template member function doTheActualSomething
. Here is how:
template<typename A, typename B>
struct Worker
{
B doTheActualSomething(Thing<A,B> *thing)
{
return thing->b_;
}
};
//partial specialization of the class template itself, for B = int
template<typename A>
struct Worker<A,int>
{
int doTheActualSomething(Thing<A,int> *thing)
{
return thing->b_ + 1;
}
};
Notice that you can use thing
pointer to access any member of the class. Of course, if it needs to access private members, then you've to make struct Worker
a friend of Thing
class template, as:
//forward class template declaration
template<typename T, typename U> struct Worker
template <class A, class B>
class Thing
{
template<typename T, typename U> friend struct Worker; //make it friend
//...
};
Now delegate the work to the friend as:
template <class A, class B>
B Thing<A,B>::doSomething()
{
return Worker<A,B>::doTheActualSomething(this); //delegate work
}
Two points to be noted here:
- In this solution,
doTheActualSomething
is not a member function template. Its not enclosing class which is template. Hence we can partially specialize the class template anytime, to get the desired effect of the partial member function template specialization. - Since we pass
this
pointer as argument to the function, we can access any member of the classThing<A,B>
, even private members, asWorker<T,U>
is also a friend.
Complete online demo : http://www.ideone.com/uEQ4S
Now there is still a chance of improvement. Now all instantiations of Worker
class template are friends of all instantiation of Thing
class template. So we can restrict this many-to-many friendship as:
template <class A, class B>
class Thing
{
friend struct Worker<A,B>; //make it friend
//...
};
Now only one instantiation of Worker
class template is a friend of one instantiation of Thing
class template. That is one-to-one friendship. That is, Worker<A,B>
is a friend of Thing<A,B>
. Worker<A,B>
is NOT a friend of Thing<A,C>
.
This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all:
http://www.ideone.com/6a1Ih
Partial template specialization of a single method of a bigger class
You can't partially specialize function templates, but you can pass the work off to class templates. Here's a fully working example:
#include<iostream>
using namespace std;
// This first template isn't important, it's just the return value from your function
template <int N, int M>
struct TransitionMatrixTemplate {
void print_me() const {
cout << N << ',' << M << endl;
}
};
// We need to announce the existence of the BaumWelch class template early here,
// in order that it can appear in the signature of our impl_randomA class.
template<int N, int M, int K>
struct BaumWelch;
// Now, the first important bit of code. The default implementation
template<int N, int M, int K>
struct impl_randomA {
static TransitionMatrixTemplate<N,M> f(BaumWelch<N,M,K> * This) {
return TransitionMatrixTemplate<N,M>();
}
};
// Next, is the partially specialized version.
template<int M, int K>
struct impl_randomA<1,M,K> {
static TransitionMatrixTemplate<1,M> f(BaumWelch<1,M,K> * This) {
cout << "<Special for N=1> ";
return TransitionMatrixTemplate<1,M>();
}
};
// Finally, The BaumWelch class and its call out to impl_randomA.
template<int N, int M, int K>
struct BaumWelch {
const TransitionMatrixTemplate<N, M> randomA() {
return impl_randomA<N,M,K> :: f(this);
}
};
int main() {
BaumWelch<2,3,4>() . randomA() . print_me();
BaumWelch<1,3,4>() . randomA() . print_me();
}
What is wrong with partial template specialization?
You are trying to partially specialize a method. That is not allowed. You can only partially specialize the whole class. Once you have specialized the class, you can then provide a non-specialized definition of the methods for the partially specialized class.
Here is an example of some code that might do what you want:
template<class T, bool p = true>
class A
{
private:
T* ptr;
public:
A();
};
template <class T>
class A<T,true> {
private:
T* ptr;
public:
A();
};
template <class T>
class A<T,false> {
private:
T* ptr;
public:
A();
};
template<class T>
A<T,true>::A()
{
ptr = reinterpret_cast<T *>(0xbaadf00d);
}
template<class T>
A<T,false>::A()
{
ptr = 0;
}
int main()
{
A<int> obj;
A<int, false> o;
return(0);
}
C++: partial specialization of template template classes
Function templates may only be fully specialized, not partially.
Member functions of class templates are automatically function templates, and they may indeed be specialized, but only fully:
template <>
void Foo<int, Goo>::foo1() { } // OK
You can partially specialise the entire class and then define it anew:
template <typename A>
struct Foo<A, Goo>
{
// ...
};
(See 14.7.3 for details.)
A workaround for partial specialization of function template?
Anytime you ask yourself "how to simulate partial specialization for functions", you can think "overload, and let partial ordering decide what overload is more specialized".
template<int N>
using int_ = std::integral_constant<int, N>;
class Meta
{
template<int N, typename T> static constexpr T ipow(T x)
{
return ipow<N, T>(x, int_<(N < 0) ? -1 : N>());
}
template<int N, typename T> static constexpr T ipow(T x, int_<-1>)
{
// (-N) ??
return static_cast<T>(1) / ipow<-N>(x, int_<-N>());
}
template<int N, typename T> static constexpr T ipow(T x, int_<N>)
{
return x * ipow<N-1>(x, int_<N-1>());
}
template<int N, typename T> static constexpr T ipow(T x, int_<0>)
{
return 1;
}
};
I think you wanted to pass -N
instead of N
at the comment-marked position.
Partial specialization of templates with integer parameters
As a rule any form of partial template specialisation is not allowed for functions. However it is allowed for classes. So the solution is simply to move your function to a static member of a templated holder class.
If you need to deduce the template arguments, you can then just create a wrapper function that calls the templated class.
The result is something like this:
template<int Index, typename Tpl>
class CalcInterleaveByteOffsetImpl
{
static size_t CalcInterleaveByteOffset(const Tpl &t)
{
// This is OK it calls the wrapper function
// You could also do
// size_t prevOffset = CalcInterleaveByteOffsetImpl<Index - 1, Tpl>::CalcInterleaveByteOffset(t);
size_t prevOffset = ::CalcInterleaveByteOffset<Index - 1>(t);
return prevOffset + sizeof(Tpl);
}
};
template<typename Tpl>
class CalcInterleaveByteOffsetImpl<0, Tpl>
{
static size_t CalcInterleaveByteOffset(const Tpl &t)
{
return 0;
}
};
template<int Index, typename Tpl>
size_t CalcInterleaveByteOffset(const Tpl &t)
{
return CalcInterlaveByteOffsetImpl<Index,Tpl>::CalcInterleaveByteOffset(t);
}
Related Topics
String-Interning at Compiletime for Profiling
How to Iterate Through Every Possible Combination of N Playing Cards
Error Redeclaring a for Loop Variable Within the Loop
Why Do I Get a Template Error If I Name My Function 'Swap', But 'Swap' Is Okay
How Does the Stl's Multimap Insert Respect Orderings
C/C++ Counting the Number of Decimals
How to Build a Program Using C++ Driver of Mongodb
Why Isn't "0F" Treated as a Floating Point Literal in C++
What Are the Incompatible Differences Between C(99) and C++(11)
Error: "No Match for Operator+" , for List Iterator
How to Set Given Channel of a Cv::Mat to a Given Value Efficiently Without Changing Other Channels