If I Want to Specialise Just One Method in a Template, How to Do It

If I want to specialise just one method in a template, how do I do it?

You can provide a specialization for only that function outside the class declaration.

template <typename T> struct Node
{
// general method split
void split()
{
// implementation here or somewhere else in header
}
};

// prototype of function declared in cpp
void splitIntNode( Node & node );

template <>
void Node<int>::split()
{
splitIntNode( this ); // which can be implemented
}

int main(int argc, char* argv[])
{
Node <char> x;
x.split(); //will call original method
Node <int> k;
k.split(); //will call the method for the int version
}

If splitIntNode needs access to private members, you can just pass those members into the function rather than the whole Node.

specialize only (a part of) one method of a template class

You can use specialization like that (no need to specialize the whole class):

template<>
std::string C<string>::method3(string &t) {
// ...
std::string s = t;
// ...
return s;
}

Specializing single method in a big template class

In addition to the inheritance-based solution proposed by Torsten, you could use std::enable_if and default function template parameters to enable/disable certain specializations of the function.

For example:

template<typename T>
struct comparer
{
template<typename U = T ,
typename std::enable_if<std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return /* floating-point precision aware comparison */;
}

template<typename U = T ,
typename std::enable_if<!std::is_floating_point<U>::value>::type* = nullptr>
bool operator()( U lhs , U rhs )
{
return lhs == rhs;
}
};

We take advantage of SFINAE to disable/enable the different "specializations" of the function depending on the template parameter. Because SFINAE can only depend on function parameters, not class parameters, we need an optional template parameter for the function, which takes the parameter of the class.

I prefer this solution over the inheritance based because:

  • It requires less typing. Less typing probably leads to less errors.
  • All specializations are written inside the class. This way to write the specializations holds all of the specializations inside the original class , and make the specializations look like function overloads, instead of tricky template based code.

But with compilers which have not implemented optional function template parameters (Like MSVC in VS2012) this solution does not work, and you should use the inheritance-based solution.

EDIT: You could ride over the non-implemented-default-function-template-parameters wrapping the template function with other function which delegates the work:

template<typename T>
struct foo
{
private:
template<typename U>
void f()
{
...
}

public:
void g()
{
f<T>();
}
};

Of course the compiler can easily inline g() throwing away the wrapping call, so there is no performance hit on this alternative.

Template specialization of a single method from a templated class

As with simple functions you can use declaration and implementation.
Put in your header declaration:

template <>
void TClass<int>::doSomething(std::vector<int> * v);

and put implementation into one of your cpp-files:

template <>
void TClass<int>::doSomething(std::vector<int> * v) {
// Do somtehing with a vector of int's
}

Don't forget to remove inline (I forgot and thought this solution will not work :) ).
Checked on VC++2005

Template specialization with only one parameter

It's called a partial template specialization:

template <class T, unsigned Capacity>
struct Collection {

};

template <unsigned Capacity>
struct Collection<Pair, Capacity> {
// Specialize
};

One thing to note is that you cannot partially specialize a single function. You have to specialize the whole class template, which is irritating if the class template is long. Another quick-and-dirty way of doing this if you want to specialize a single function would be to just use a "compile-time if":

#include <type_traits>

template <class T, unsigned Capacity>
struct Collection {
void display() const {
if constexpr (std::is_same_v<T, Pair>) {
// pair implementation
} else {
// general implementation
}
}
};

Or, as a more clean solution, try moving the whole thing out of the class and add a simple overload:

// Free-standing overloads:

template <class T, unsigned Capacity>
void diplay(Collection<T, Capacity> const& c) { /* ... */ }

template <unsigned Capacity>
void display(Collection<Pair, Capacity> const& c) { /* ... */ }

// The member function delegates the work to
// the overloaded functions. No template specialization
// is involved:

template <class T, unsigned Capacity>
struct Capacity {
void display() const {
display(*this); // calls the correct overload.
}
};

C++ specialize single method in template class

You can either change it to

template<typename U = T, typename std::enable_if<
!std::is_base_of<BaseClass, U>::value>::type* = nullptr>
void print_line()
{
std::cout << "Parameter of general Type T" << std::endl;
}

or

template<typename U = T>
typename std::enable_if<!std::is_base_of<BaseClass, U>::value, void>::type print_line()
{
std::cout << "Parameter of general Type T" << std::endl;
}

and the other one accordingly.

The idea behind both is to produce an error for one of the methods during the instantiation of the function templates. Due to the error, the corresponding method is not considered during overload resolution such that there is only one method (the one that did not produce the error) available, which will then be called.
std::enable_if is used to produce this error, because if its first parameter is false it does not define a type member so the function template cannot be instantiated and will be removed from overloading resolution.

Search for SFINAE for more detailed information.

Is it possible to specialize a method of a template class on another templated class?

Just using c++20 contrians:

template <typename V>
struct A {
void foo() { std::cout << "A<V>\n"; }

void foo() requires (std::same_as<V, std::vector<typename V::value_type>>) {
std::cout << "A<V<T>>\n";
}
};

Then this works:

A<int>{}.foo(); // call normal one
A<std::vector<int>>{}.foo(); // call specialized one

How to specialize a template class method for a specific type?

  1. You should make both the overloading of print() to function template (to make SFINAE working), otherwise the non-template function is always preferred.

  2. You should let print() taking its own template type parameter; type cheking shouldn't be performed on the class template parameter T directly, function templates overload resolution and SFINAE are performed on the function templates themselves, the class template doesn't involve in.

  3. You can move the part of std::enable_if to the return type.

  4. You should change the order specified to std::is_base_of (i.e. std::is_base_of<Bar, X>, not std::is_base_of<X, Bar>) if you want the type to be Bar or the derived class of Bar.

e.g.

template <typename X = T>
typename std::enable_if<std::is_base_of<Bar, X>::value>::type print() {
t.print();
}

template <typename X = T>
typename std::enable_if<!std::is_base_of<Bar, X>::value>::type print() {
std::cout << t << std::endl;
}

LIVE



Related Topics



Leave a reply



Submit