2016-06-08 12 views
6

Wdrażam system RPC przeznaczony do wykonywania zadań w zdalnych procesach. Jeden węzeł systemu RPC to Monitor, który powinien rejestrować każde wywołanie.Przechowywanie i zwracanie ogólnego typu (nawet nieważne) z funkcji

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; 
}; 

Działa dobrze, z wyjątkiem jednego przypadku, gdy Metoda: Wynik jest nieważny. Aby obejść ten musiałem podzielić operatora() na 2 części

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; 
} 

Czy istnieje jakiś sposób, aby wyeliminować kopiuj-wklej, przy założeniu, że linia journal("<-", Method::Name()); nie powinny być wykonywane w przypadku wystąpienia wyjątku (więc nie mogę wrap logging in construct/destructor)?

Odpowiedz

2

Możesz można zapisać log wewnątrz obiektu RAII. Po prostu sprawdź, czy wyjątek jest aktualnie w locie przed drukowaniem w destruktorze, co można zrobić z std::uncaught_exception (która stanie się std::uncaught_exceptions w C++ 17).


Jeśli potrzebna jest coś bardziej elastyczny, można użyć otoki dla wartości zwracanej, specjalizujący się go za 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 wykonuje wywołanie funkcji i zapisuje wynik, który może być później przeniesiony za pośrednictwem value(). To wiąże się z możliwością powrotu wyrażenie void -type z void funkcji:

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

Dziękuję za sugestię. Nigdy wcześniej nie słyszałem o std :: uncaughttexexception. Jedynym minusem jest to, że kontrola wykonywana jest w czasie pracy i muszę zapłacić za nią wydajność – sliser

Powiązane problemy