2016-06-08 40 views
6

存儲和返回泛型類型(甚至無效)我正在實現一個RPC系統,旨在執行遠程過程中的任務。 RPC系統的一個節點是Monitor,它應記錄每個呼叫。從函數

template<typename Transport, typename Journal> 
class Monitor 
{ 
public: 
    Monitor(Transport transport, Journal &journal) : 
     transport{std::move(transport)}, 
     journal{journal} 
    { 
    } 

public: 
    template<typename Method> 
    typename Method::Result operator()(const Method &method) 
    { 
     Method::Result result; 
     journal("->", Method::Name()); 
     result = transport(method); 
     journal("<-", Method::Name()); 
     return result; 
    } 

private: 
    Transport transport; 
    Journal &journal; 
}; 

它工作正常,除了一個情況下,當Method :: Result是無效的。要解決此我不得不運營商()分割成兩個部分

template<typename Transport, typename Journal> 
template<typename Method> 
std::enable_if_t<std::is_same<typename Method::Result, void>::value, typename Method::Result> operator()(const Method &method) 
{ 
    journal("->", Method::Name()); 
    transport(method); 
    journal("<-", Method::Name()); 
} 

template<typename Transport, typename Journal> 
template<typename Method> 
std::enable_if_t<!std::is_same<typename Method::Result, void>::value, typename Method::Result> operator()(const Method &method) 
{ 
    Method::Result result; 
    journal("->", Method::Name()); 
    result = transport(method); 
    journal("<-", Method::Name()); 
    return result; 
} 

有什麼辦法消除複製粘貼,假設行journal("<-", Method::Name());不應例外(的情況下執行的,所以我不能在構造/析構函數中包裝日誌記錄)?

回答

2

您可以可以將記錄封裝在RAII對象內。只需檢查在析構函數中打印之前是否有異常正在運行,這可以用std::uncaught_exception(它將在C++ 17中變成std::uncaught_exceptions)完成。


如果需要的東西更靈活,你可以使用一個包裝你的返回值,專攻它void

template <class T> 
struct RetWrapper { 
    template <class Tfunc, class... Targs> 
    RetWrapper(Tfunc &&func, Targs &&... args) 
    : val(std::forward<Tfunc>(func)(std::forward<Targs>(args)...)) {} 

    T &&value() { return std::move(val); } 

private: 
    T val; 
}; 

template <> 
struct RetWrapper<void> { 
    template <class Tfunc, class... Targs> 
    RetWrapper(Tfunc &&func, Targs &&... args) { 
     std::forward<Tfunc>(func)(std::forward<Targs>(args)...); 
    } 

    void value() {} 
}; 

RetWrapper執行函數調用和存儲結果,以後可以通過value()搬出。這種關係在從void函數返回一個void型表達的可能性:

template<typename Method> 
typename Method::Result operator()(const Method &method) 
{ 
    journal("->", Method::Name()); 
    RetWrapper<typename Method::Result> retVal{transport, method}; 
    journal("<-", Method::Name()); 
    return retVal.value(); 
} 

Live on Coliru

+0

謝謝你的建議。從來沒有聽說過std :: uncaught_exception。唯一的缺點是檢查是在運行時執行的,我必須爲它付出性能損失 – sliser