I need partial specialization of the struct
, but I'd like also use some common functionality. For example, suppose I have the next type:
template <typename A, typename B>
struct Foo
{
Foo& func0() { /* common actions with A and B */; return *this; }
void func1() { /* common actions with A and B */ }
void func2() { /* common actions with A and B */ }
}
Then I want specialize it for one of the template parameters - for example, I want consider special case when B
is int
, and I want to preserve func0
and func1
behaviour exactly the same as in common Foo
(or course, func0()
must return my specialized Foo&
for int
), func2
I want rewrite (suppose that I have more efficient implementation of it for integers), and I also want add func3()
only for my specialized Foo
.
Of course, I can simpy write the following:
template <typename A>
struct Foo<A, int>
{
Foo& func0() { /* common actions with A and B */; return *this; }
void func1() { /* common actions with A and B */ }
void func2() { /* actions with A and 'int' */ }
void func3() { /* actions with A and 'int' */ }
}
but I'd like to avoid copy-paste in func0
and func1
.
I also can rename common Foo
to something like FooBase
and simply inherit Foo
from it, but in this case I can't use the common case as
Foo<float, float> a;
What methods does exist for allow me using both
Foo<float, float> a;
and
Foo<float, int> b;
without copying and pasting common Foo
's code to specialization?
I'm interested in both c++11 and earlier standard compatibility.
This seems to work for me.
template <typename A, typename B>
struct Foo;
template <typename A, typename B>
struct FooBase
{
Foo<A, B>& func0()
{
cout << "FooBase:func0\n";
return static_cast<Foo<A, B>&>(*this);
}
void func1() { cout << "FooBase::func1\n"; }
void func2() { cout << "FooBase::func2\n"; }
};
template <typename A, typename B>
struct Foo : public FooBase<A, B> {
};
template <typename A>
struct Foo<A, int> : public FooBase<A, int>
{
void func2() { cout << "Foo<A, int>::func2\n"; }
void func3() { cout << "Foo<A, int>::func3\n"; }
};
If you wind up needing the definition of Foo within FooBase, you may need to use the CRTP trick of passing the derived class as a template parameter to FooBase, but for simple things I think the forward declaration is sufficient.
You can use tag-dispatching:
template <typename A, typename B>
struct Foo
{
decltype(func0(std::is_same<B, int>{})) func0()
{
return func0(std::is_same<B, int>{});
}
void func1() { /* common actions with A and B */ }
void func2() { /* common actions with A and B */ }
private:
Foo& func0(std::true_type) { func0_common(); return *this; }
void func0(std::false_type) { func0_common(); }
void func0_common() { /* common actions with A and B */ }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With