问题
I want to write 5 different classes, each of which has many member functions which are exactly the same, except of one, which is special for each class. Can I write this avoiding code duplication?
Regards, Aleksejs
Below is a very shortened version of my code, which throws the error:
template_test.cpp:15:35: error: invalid use of incomplete type ‘class impl_prototype<cl, 1>
#include <iostream>
using namespace std;
template <int cl, int dim>
class impl_prototype {
public:
impl_prototype() {}
int f(int x) { return cl + 2 * g(x); }
int g(int x) { return cl + 1 * x;}
};
template <int cl>
int impl_prototype<cl, 1>::g(int x) { return cl + 3 * x; }
int main ()
{
impl_prototype<0, 0> test_0;
impl_prototype<0, 1> test_1;
cout << test_0.f(5) << " " << test_0.g(5) << std::endl;
cout << test_1.f(5) << " " << test_1.g(5) << std::endl;
return 0;
}
回答1:
Member functions of class templates can be explicitly specialized but not partially specialized.
Just make a helper function object that you can partially specialize:
#include <iostream>
using namespace std;
template<int cl, int dim>
struct g_impl
{
int operator()(int x) { return cl + 1 * x;}
};
template<int cl>
struct g_impl<cl, 1>
{
int operator()(int x) { return cl + 3 * x; }
};
and then call that helper (the tempoary function object will optimized away):
template <int cl, int dim>
class impl_prototype
{
public:
impl_prototype() {}
int f(int x) { return cl + 2 * g(x); }
int g(int x) { return g_impl<cl, dim>()(x); }
};
int main ()
{
impl_prototype<0, 0> test_0;
impl_prototype<0, 1> test_1;
cout << test_0.f(5) << " " << test_0.g(5) << std::endl;
cout << test_1.f(5) << " " << test_1.g(5) << std::endl;
return 0;
}
Live Example
回答2:
An other method is Tag dispatching, something like:
template <int cl, int dim>
class impl_prototype
{
int g(int x, std::integral_constant<int, 1>) { return cl + 3 * x; }
template <int I>
int g(int x, std::integral_constant<int, I>) { return cl + 1 * x; }
public:
int f(int x) { return cl + 2 * g(x); }
int g(int x) { return g(x, std::integral_constant<int, dim>());}
};
回答3:
You have several options.
use inheritance, where you specialise the base class template and add the multitude of other identical member functions only with the derived class templates.
declare a helper class (function object) that is partially specialised and called from
impl_prototype<>::g()
. This is very similar to 1., but avoids inheritance (for an example, see the answer by TemplateRex);use SFINAE to "specialise" the member function:
template<int cl, int dim> class impl_prototype { template<bool dim_equals_one> typename std::enable_if<!dim_equals_one,int>::type _g(const int x) const { return cl+1*x; } template<bool dim_equals_one> typename std::enable_if< dim_equals_one,int>::type _g(const int x) const { return cl+3*x; } public: int f(const int x) const { return cl+2*g(x); } int g(const int x) const { return _g<dim==1>(x); } };
I often use this last approach as it avoids all the issues of inheritance (in particular in the case of non-trivial constructors) and any helper objects outside the class.
In your particular example, a much simpler possibility is
template<int cl, int dim>
class impl_prototype
{
public:
int f(const int x) const { return cl + 2 * g(x); }
int g(const int x) const { return cl + (dim==1? 3*x : x); }
};
来源:https://stackoverflow.com/questions/25119444/c-specialize-template-class-function-without-duplicating-code