Reputation: 1673
Please accept my apologies in advance for the somewhat long-winded question. This is the minimal self-contained example I could come up with... I'm pretty sure there must be some obvious/nice/neat solution to this problem, but I'm currently not able to see it.
Ok, here's the problem: Imagine the following situation (nb. a compileable version of the code is available at http://goo.gl/dhRNex). Suppose
struct Thing1 {
public:
void bar(class Implementation1 &i) {
i.baz();
}
// ...various other methods like bar()
};
struct Thing2 {
public:
void bar(class Implementation2 &i) {
i.qux();
}
// ...various other methods like bar()
};
are given. Unfortunately, these classes are fixed, i.e., can not be changed/refactored.
However, Implementation1
and Implementation2
are changeable. These two classes share a lot of similar code, so it seems natural to put the shared code in a common base class. However, the code is dependent the type of Thing
used, but there is no common base class for Thing1
and Thing2
, so it seems also natural to use templates. Thus, I came up with the following solution for the base class
template<class T, class S>
struct ImplementationBase {
public:
S *self;
void foo() {
T thing;
thing.bar(*self);
}
// ...lots more shared code like foo()
};
and concrete implementations
struct Implementation1 : public ImplementationBase<class Thing1, class Implementation1> {
public:
Implementation1() {
self = this;
}
void baz() {
std::cout << "Qux!" << std::endl;
}
};
struct Implementation2 : public ImplementationBase<class Thing2, class Implementation2> {
public:
Implementation2() {
self = this;
}
void qux() {
std::cout << "Qux!" << std::endl;
}
};
Ideally, one would use this
instead of self
in foo
, but the problem is that this
is of type ImplementationBase<class Thing1, class Implementation1>
, but Implementation1
is required. Obviously, the whole thing is quite a mess and the Implementation
and Thing
classes are too tightly coupled, but I cannot see an easy way out without being able to refactor the Thing
classes. So, finally, my questions are:
self
trick above?If you have made it this far, thanks a lot for taking the time and reading the whole story and my apologies again for this long-winded question.
Upvotes: 3
Views: 87
Reputation: 2234
You're already using CRTP so you don't need the self at all:
template<class T, class S>
struct ImplementationBase {
public:
S* getThis() { return static_cast<S*>(this); }
void foo() {
T thing;
thing.bar(*getThis());
}
// ...lots more shared code like foo()
};
Upvotes: 2