2013-08-06 22 views
2

假設我有一個類:增廣的一類/純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(); 

電話將被記錄。也許新的省略號運算符(...)可以派上用場嗎?

+1

Decorator模式http://stackoverflow.com/questions/2988066/decorator-pattern-in-c – doctorlove

回答

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++有沒有(靜態)反射。

+0

這是很好的。我相信一個很好的宏可以隱藏lambda表達式的一大部分。 –

2

擴大Xeo的答案,如果您使用decltyperesult_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; 
}