2

假设我有一堂课:

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

呼叫将被记录。也许新的省略号运算符 ( ...) 可以在这里派上用场?

4

2 回答 2

6

这不是直接可能的,因为您无法检查一个类来查看它有哪些成员。

但是,您可以做一些接近的事情:

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++ 没有(静态)反射。

于 2013-08-06T08:41:53.073 回答
3

扩展 Xeo 的答案,如果你使用decltypeorresult_of而不是auto &&你也会得到复制省略。

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;
}
于 2013-08-07T10:02:44.107 回答