Specializing Single Method in a Big Template Class

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

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.

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

Template specialization of a single method from templated class with multiple template parameters

You have to specialize the entire class before you define a method through a partial specialization:

template <typename T, typename U>
class TClass;

template <typename T>
class TClass<int, T>
{
void doSomething(int* v);
};

template <typename T>
void TClass<int, T>::doSomething(int* v)
{
// ...
}

Live demo

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.

Class template specializing a method c++

(1) Sort of, but not quite the way you're trying to do it. You basically want the specializations to define the function; it's quite a bit different from when you are declaring base and derived classes.

template <typename T> class Shape {
static_assert(false, "Not implemented");
};

template <> class Shape<bool> {
void Foo(bool a, std::string b) {...}
};

template <> class Shape<int> {
void Foo(int, std::string, whatever else) {...}
};

Even if you were to define Foo in the original non-specialized Shape, it would have no effect on the specializations. Full specializations don't extend the original template, they replace it!

(2) Use static_assert. See the example above.

(3) Yes, you can mix templates and inheritence. Virtual functions runtime polymorphism and static polymorphism. Template parameters have to be known at compile time whereas the exact type of a runtime polymorphic object does not, because they can be referred to by a base class reference. In the templated example above you cannot simply say

template <class T> Shape {...};

...

Shape* myShape; // Compiler error: Shape requires a template parameter

However with inheritence you can:

class ShapeBase { virtual void Foo() = 0; };
class Circle : public ShapeBase { virtual void Foo() { ... } };
class Square : public ShapeBase { virtual void Foo() { ... } };
...

Shape* myShape = new Circle;
myShape->Foo(); // calls Circle->Foo()

Note when you're working with inheritence, the function signatures DO have to match! That's the price you pay for deferring the decision till runtime.

Specializing Template Classes with Parameter Packs

The problem is that your specializations are of the same level (no one is more specialized that the other) and Child<void> matches both.

If you want that Child<void> matches the Child<ReturnTy> case (otherwise the solution is simple and elegant: in the second specialization, split the ParamTypes... list in a Par0 mandatory type and the rest of the ParamTypes...) I don't see a simple and elegant solution.

The best I can imagine, at the moment, is add a level of indirection (add a Child_base class) adding also a template parameter to explicit the desired solution.

Maybe can be made in a simpler way (sorry but, in this moment, I can try with a compiler) but I imagine something as follows

template <typename RT, bool, typename ... PTs>
class Child_base : public Interface
{
// general case (no empy PTs... list and no void return type)
};

template <typename ... PTs>
class Child_base<void, true, PTs...> : public Interface
{
// case return type is void (also empy PTs... list)
};

template <typename RT>
class Child_base<RT, false> : public Interface
{
// case return type only, but not void, and empy PTs
};

template <typename RT, typename ... PTs>
class Child
: public Child_base<RT, std::is_same_v<void, RT>, PTs...>
{
};

This way, Child<void> inherit from Child_base<void, true> that matches the first specialization of Child_base but doesn't match the second one.

I propose another way about Child: instead of define it as a class derived from Child_base, you can try defining it as a using alias of Child_base

template <typename RT, typename ... PTs>
using Child = Child_base<RT, std::is_same_v<void, RT>, PTs...>;

Maybe renaming Child_base with a more appropriate name.



Related Topics



Leave a reply



Submit