Can a Single Member of a Class Template Be Partially Specialized

Can a single member of a class template be partially specialized?

The notion of partial specialization only exists for class templates (described by §14.5.5) and member templates (i.e. members of a template class that are themselves template functions, described by §14.5.5.3/2). It does not exist for ordinary members of class templates, nor does it exist for function templates – simply because it is not described by the Standard.

Now, you might argue that by giving the definition of a partial specialization of a member function, such as

template <typename T>
void Foo<T,int>::f()
{ }

you implicitly define a partial specialization of the class template: Foo<T,int>. That, however, is explicitly ruled out by the Standard:

(§14.5.5/2) Each class template partial specialization is a distinct template and definitions shall be provided for the members of a template partial specialization (14.5.5.3).

(§14.5.5.3/1) [...] The members of the class template partial specialization are unrelated to the members of the primary template. Class template partial specialization members that are used in a way that requires a definition shall be defined; the definitions of members of the primary template are never used as definitions for members of a class template partial specialization. [...]

The latter implies that it is impossible to implicitly define a partial specialization by simply giving the definition of one of its members: The very existence of that member would not follow from the definition of the primary template, hence defining it is equivalent to defining a member function that wasn't declared, and that isn't allowed (even with non-template classes).

On the other hand, the notion of explicit specialization (or full specialization, as you call it) exists for member functions of class templates. It is explicitly described by the Standard:

(§14.7.3/1) An explicit specialization of any of the following:

[...]

— member function of a class template

[...]

can be declared by a declaration introduced by template<>; [...]

§14.7.3/14 describes the details:

(§14.7.3/14) A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template, even if the member or member template is defined in the class template definition. [...]

Hence, for explicit specializations of members, the instantiation of the rest of the class template works implicitly – it is derived from the primary template definition, or any partial specializations if defined.

c++ class template partial specialization without specializing all member functions

In my experience use inheritance method (2) when you actually want a new class that inherits from the template. Use method (1) when the partial specialization is sufficiently different from the general case or general case is not defined at all and you just declare a bunch of partial specializations to make use of SFINAE.

If you simply want to enable/disable methods of a class based on template parameters then utilize SFINAE. As this way you can centralize all your definitions in one place and reason about them more easily. This is the preferred method unless you want user to make the template specializations on their own - which isn't desirable in general.

Example of SFINAE:

template <class T, size_t N>
class X {
public:
void a() {...};
X<T, N> b(X<T, N> x);
// etc
static X<T, n> c() {...};

template<size_t uN = N, std::enable_if_t<uN==3,int>=0>
void d() {...};
protected:
T data[N];
};

Here, X<int,3> x; x.d(); will compile but X<int,2> x; x.d(); will not as d() method is disabled unless N==3.

You can read a lot more about usages of SFINAE in template functions and classes in numerous online guides (note that the syntax is quite different for functions and classes).

Why is partial specialization of a nested class template allowed, while complete isn't?

My guess as to why this happens: complete specializations are no longer "template classes/functions", they are are "real" classes/methods, and get to have real (linker-visible) symbols. But for a completely-specialized template inside a partially-specialized one, this would not be true.
Probably this decision was taken just to simplify the life of compiler-writers (and make life harder for coders, in the process :P ).

C++ template partial specialization - specializing one member function only

Second solution (correct one)

template <typename T>
class foo
{
public:
void addSome (T o) { printf ("adding that object..."); }
void deleteSome(T o) { deleteSomeHelper<T>()(o); }
protected:
template<typename TX>
struct deleteSomeHelper { void operator()(TX& o) { printf ("deleting that object..."); } };
template<typename TX>
struct deleteSomeHelper<TX*> { void operator()(TX*& o) { printf ("deleting that PTR to an object..."); } };
};

This solution is valid according to Core Issue #727.


First (incorrect) solution: (kept this as comments refer to it)

You cannot specialize only part of class. In your case the best way is to overload function deleteSome as follows:

template <typename T>
class foo
{
public:
void addSome (T o) { printf ("adding that object..."); }
void deleteSome (T o) { printf ("deleting that object..."); }
void deleteSome (T* o) { printf ("deleting that object..."); }
};

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();
}

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 class Thing<A,B>, even private members, as Worker<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

Why function template cannot be partially specialized?

AFAIK that's changed in C++0x.

I guess it was just an oversight (considering that you can always get the partial specialization effect with more verbose code, by placing the function as a static member of a class).

You might look up the relevant DR (Defect Report), if there is one.

EDIT: checking this, I find that others have also believed that, but no-one is able to find any such support in the draft standard. This SO thread seems to indicate that partial specialization of function templates is not supported in C++0x.

EDIT 2: just an example of what I meant by "placing the function as a static member of a class":

#include <iostream>
using namespace std;

// template<typename T, typename U> void f() {} //allowed!
// template<> void f<int, char>() {} //allowed!
// template<typename T> void f<char, T>() {} //not allowed!
// template<typename T> void f<T, int>() {} //not allowed!

void say( char const s[] ) { std::cout << s << std::endl; }

namespace detail {
template< class T, class U >
struct F {
static void impl() { say( "1. primary template" ); }
};

template<>
struct F<int, char> {
static void impl() { say( "2. <int, char> explicit specialization" ); }
};

template< class T >
struct F< char, T > {
static void impl() { say( "3. <char, T> partial specialization" ); }
};

template< class T >
struct F< T, int > {
static void impl() { say( "4. <T, int> partial specialization" ); }
};
} // namespace detail

template< class T, class U >
void f() { detail::F<T, U>::impl(); }

int main() {
f<char const*, double>(); // 1
f<int, char>(); // 2
f<char, double>(); // 3
f<double, int>(); // 4
}

c++ template partial specialization member function

You cannot partially specialize only a single member function, you must partially specialize the whole class. Hence you'll need something like:

template <typename T>
class Object<T, 0>
{
private:
T m_t;
Object();
public:
Object(T t): m_t(t) {}
T Get() { return m_t; }
Object& Deform()
{
std::cout << "Spec\n";
m_t = -1;
return *this;
}
};


Related Topics



Leave a reply



Submit