Предположим, у меня есть класс:
class Widget {
public:
void initialize() {
// hurr-durr
};
int computeAnswer() {
return -42;
};
std::string getQuestion() {
return "The question";
};
};
Он выполняет некоторые вычисления, может делать все, что захочет.
Теперь я хочу расширить его — применить аспект, скажем, тот, который регистрирует каждый вызов метода.
Если бы я реализовал это вручную, Я бы реализовал все методы таким образом:
int LoggingWidget::computeAnswer(){
log << 'Calling method computeAnswer';
int result = Widget::computerAnswer();
log << 'Result = ' << result;
return result;
}
Я бы хотел, чтобы решение было как можно более общим (Я не хочу вручную переадресовывать все звонки), поэтому возможное использование может включать один из них (в зависимости от того, что возможно)
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.
так что когда я звоню
int result = w.computeAnswer();
Звонки будут зарегистрированы. Возможно новый оператор многоточия (...
) может пригодиться здесь?
Это невозможно напрямую, так как вы не можете проверить класс, чтобы увидеть, какие члены у него есть.
Тем не менее, вы можете сделать что-то близкое:
Logging<Widget> w(widget);
w([&](Widget& w){
return w.computeAnswer();
});
куда Logging::operator()
выглядит следующим образом:
/* 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;
}
Это не станет намного лучше, чем это для полностью общего кода, так как C ++ не имеет (статического) отражения.
Расширяя ответ Xeo, если вы используете decltype
или же result_of
скорее, чем auto &&
вы также получаете копию elision.
template<typename F>
auto operator()(F &&f) -> decltype(std::forward<F>(f)(wrapped))
{
pre_log();
decltype(std::forward<F>(f)(wrapped)) result = std::forward<F>(f)(wrapped);
post_log(result);
return result;
}
В C ++ 14 вы можете сократить это до:
template<typename F>
decltype(auto) operator()(F &&f)
{
pre_log();
decltype(auto) result = std::forward<F>(f)(wrapped);
post_log(result);
return result;
}