Suppose I have a class:
class Widget {
public:
void initialize() {
// hurr-durr
};
int computeAnswer() {
return -42;
};
std::string getQuestion() {
return "The question";
};
};
It performs some computation, can do whatever it wants.
Now I want to augment it - apply an aspect, say one that logs each method call.
If I implemented this by hand, I'd implement all methods in this fashion:
int LoggingWidget::computeAnswer(){
log << 'Calling method computeAnswer';
int result = Widget::computerAnswer();
log << 'Result = ' << result;
return result;
}
I'd like the solution to be as generic as possible (I don't want to manually forward all calls), so the possible usages could include one of these (whichever is possible)
Widget* w = new LoggingWidget(); // either a class that inherits from Widget
// and automatically forwards all calls.
Widget* w = new Logging<Widget>(); // or a template that does this.
so that when I call
int result = w.computeAnswer();
The calls will be logged. Perhaps the new ellipsis operator (...
) could come in handy here?
This isn't directly possible, since you can't inspect a class to see which members it has.
However, you can do something close:
Logging<Widget> w(widget);
w([&](Widget& w){
return w.computeAnswer();
});
Where Logging::operator()
looks like follows:
/* somewhere in class: T wrapped; */
template<class F>
auto operator()(F&& f)
-> decltype(f(wrapped))
{
pre_log();
auto&& result = f(wrapped);
post_log(result);
return result;
}
It won't get better much better than this for totally generic code, since C++ has no (static) reflection.