Reputation: 165
template <typename T> class FooBase {
void push(T& t) = 0;
T pop() = 0;
}
template<typename T> class FooDerived1: public FooBase<T> {
}
template<typename T> class FooDerived2: public FooBase<T> {
}
////////////////////////////////
template<typename T, typename Foo> class Bar: public Foo<pair<T, int>> {
void push(T& t) {
int value = get_val();
foo_.push(make_pair(t, v));
}
pair<T, int> pop() {
return foo_.pop();
}
Foo<pair<T, int>> foo_;
}
So basically we have different instances of class Foo, "FooDerived1", "FooDerived2" etc
We have a class Bar, which is a decorator, on top of class Foo, which should take in different any children of class Foo.
The problem is that, the decorator would initialize class FooBase's template with a modified typename. Basically change FooBase to FooBase<pair<T, int>>
Inside class Bar, I would use all of Foo's interface, and also a wrapper, around the base class function
What is the right way to do this? Because when I am trying to initialize class Bar, I am confused.
Bar<float, FooDerived1<float>> bar1;
Bar<float, FooDerived2<float>> bar2;
I am not sure how this would work and what is the right way to accomplish, what I am trying to do.
Thank you.
Upvotes: 0
Views: 108
Reputation: 122585
First, Bar
needs only a single template argument. T
can be deduced from an instantiation FooBase<T>
via a type trait, or by using a member alias.
Then you can use SFINAE to check if that argument inherits from FooBase
(which adds a second argument again):
#include <type_traits>
#include <utility>
template <typename T> struct FooBase { using type = T; };
template <typename T> struct Foo1 : FooBase<T> {};
template <typename T,typename = void> struct Bar;
template <typename T>
struct Bar< T,
std::enable_if_t<
std::is_base_of_v<
FooBase<typename T::type>,T>>
>
: FooBase<std::pair<typename T::type,int>> {};
int main() {
Bar< Foo1<int>> c;
}
Though, this would be much simpler if you drop some restrictions. If Bar<T>
does not require T
to inherit from FooBase
and if the caller instantiates it via Bar< sometype::type >
then no SFINAE is needed and Bar
could be simply template <typename T> struct Bar : FooBase<std::pair<T,int>> {};
. Also it is not clear what is the relevance of the derived class for Bar
. In your code Bar
merely uses T
and FooBase
. However, I hope the above will help.
Upvotes: 3