I know partial template specialization isn't supported for functions and class methods, so my question is: What are common solutions or patterns to resolve this? Below Derived
derives from Base
, and both of these classes have virtual methods greet()
and speak()
. Foo
's holds a std::array<unique_ptr<T>, N>
and is used in do_something()
. Foo
has two template parameters: T
(the class type) and N
(number of elements of the std::array
) If N
= 2, there exists a highly optimized version of do_something()
. Now assume that Foo
's T
parameter isn't always the base class Base
. Ideally, I would like to write the following code, but it's illegal:
//ILLEGAL
template<typename T>
void Foo<T,2>::do_something()
{
arr_[0]->greet();
}
Below is the full code and my current (ugly) solution. I have to specialize do_something()
twice, once for Base
and once for Derived
. This gets ugly if there exists multiple methods like do_something()
that can be optimized on the special N
=2 case, and if there exists many subclasses of Base
.
#include <iostream>
#include <memory>
class Base
{
public:
virtual void speak()
{
std::cout << "base is speaking" << std::endl;
}
virtual void greet()
{
std::cout << "base is greeting" << std::endl;
}
};
class Derived : public Base
{
public:
void speak()
{
std::cout << "derived is speaking" << std::endl;
}
void greet()
{
std::cout << "derived is greeting" << std::endl;
}
};
template<typename T, int N>
class Foo
{
public:
Foo(std::array<std::unique_ptr<T>, N>&& arr) :
arr_(std::move(arr))
{
}
void do_something();
std::array<std::unique_ptr<T>, N> arr_;
};
template<typename T, int N>
void Foo<T,N>::do_something()
{
arr_[0]->speak();
}
//Want to avoid "copy-and_paste" of do_something() below
template<>
void Foo<Base,2>::do_something()
{
arr_[0]->greet();
}
template<>
void Foo<Derived,2>::do_something()
{
arr_[0]->greet();
}
int main()
{
constexpr int N = 2;
std::array<std::unique_ptr<Derived>, N> arr =
{
std::unique_ptr<Derived>(new Derived),
std::unique_ptr<Derived>(new Derived)
};
Foo<Derived, N> foo(std::move(arr));
foo.do_something();
return 0;
}