I have a template class Foo<T>
that I derive in FooDerived<T>
, which is in turn the template argument of a template class Bar<T>
, i.e. I end up with something like Bar< FooDerived<T> >
.
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived : public Foo<T>
{
public:
double compute() { return 42.0; }
};
template <typename T>
class Bar : public T
{
public:
void f()
{
// This function could vary depending on U (and possibly T)
std::cout << "Bar< T<U> > : " << this->compute() << std::endl;
}
};
I am trying to specialize Bar
based on the template argument of FooDerived
. For example, Bar< FooDerived<int> >
and Bar< FooDerived<float> >
will have a different behavior.
int main(void)
{
Bar< FooDerived<int> > a;
a.f();
Bar< FooDerived<float> > b;
b.f();
}
How can I achieve this efficiently in C++03 (or C++11)? By efficiently, I mean that I want to avoid useless code duplication (the real program involves a lot more types and functions than in this example). Also, people using the code should be able to add their specialization without needing to modify the code, so any kind of switch
-like solution would not be adapted.
I have been looking at SFINAE-like solutions involving boost::mpl
, e.g. boost::mpl::if_
with boost::is_same
to check the type, but nothing seemed to achieve my objectives. I suppose that this may not be adapted for that kind of template specialization. I always end up with error: redefinition of 'Bar'
since the compiler does not seem to see it as a specialization, for instance if I try to do something like this:
template class Bar : public T, private boost::mpl::if_, int, boost::mpl::false_>
Using the boost::mpl::if_
, either as a private inheritance or an extra template argument, does not seem to make specialization possible.
So what is the proper way of achieving something like this?
UPDATE 1
Specializing all the cases is a possibility, but the real problem that hides behind this example is actually a lot more complicated. I have a CachedFunction<T> : public T
where T
derives from Function<U>
(function, differentiable function, twice differentiable function etc.) where U
is a storage type (dense or sparse matrices). CachedFunction
contains a large number of functions whose implementation depends on the storage type and the type of function. Thus, metaprogramming seemed like a good way to avoid some code duplication.
UPDATE 2
In response to the answers provided: I am trying to avoid these explicit template specialization for all the cases involved. Try to imagine that there are 3 or 4 classes derived from Foo
, that there are 2 or 3 types for Foo
, and that Bar
contains 6 or 7 functions that need to be processed differently based on the type of Foo
and the derived class considered. Basically, for each i
, j
and k
, I would need to implement:
template<> void Bar<FooDerived_i<Type_j> >::f_k(){ ... }
Thus, I am trying to see if there is any other "cleaner" way.
UPDATE 3
If I use boost::is_same
, I can do something like this, but this solution makes it harder to handle a new type without modifying the code.
Here is an example:
#include <iostream>
#include <boost/type_traits/is_same.hpp>
typedef int type1;
typedef float type2;
template <typename T>
class Foo
{
public:
typedef T type_t;
virtual double compute() { return 1.0; }
};
template <typename T>
class FooDerived
{
public:
typedef T type_t;
double compute() { return 42.0; }
};
template <class T>
class Bar : public T
{
public:
void f()
{
// types have to be known...
if (boost::is_same<typename T::type_t, type1>::value)
std::cout << "Bar< T<type1> > : " << this->compute() << std::endl;
else if (boost::is_same<typename T::type_t, type2>::value)
std::cout << "Bar< T<type2> > : " << this->compute() << std::endl;
}
};
int main(void)
{
Bar< Foo<type1> > a;
a.f();
Bar< FooDerived<type2> > b;
b.f();
}