Дополнить класс / применить аспект в чистом C ++ (C ++ 11)

Предположим, у меня есть класс:

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();

Звонки будут зарегистрированы. Возможно новый оператор многоточия (...) может пригодиться здесь?

2

Решение

Это невозможно напрямую, так как вы не можете проверить класс, чтобы увидеть, какие члены у него есть.

Тем не менее, вы можете сделать что-то близкое:

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 ++ не имеет (статического) отражения.

6

Другие решения

Расширяя ответ 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;
}
2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector