2016-06-08 4 views
6

ich ein RPC-System bin Implementierung entworfen Aufgaben in Remote-Prozesse auszuführen. Ein Knoten des RPC-Systems ist Monitor, der jeden Anruf protokollieren sollte.Speichern und Rückkehr gattungsgemäßen Art (auch void) aus Funktion

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

Es funktioniert gut außer einem Fall, wenn Methode :: Ergebnis ist ungültig. Um dies zu umgehen ich operator() in 2 Teile

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

Gibt es eine Möglichkeit Copy-Paste zu teilen hatte zu beseitigen, dass die Linie unter der Annahme journal("<-", Method::Name()); soll nicht im Fall einer Ausnahme ausgeführt werden (so kann ich nicht wrap Anmeldung in Konstrukt/Destruktor)?

Antwort

2

Sie können Wrap Protokollierung innerhalb eines RAII-Objekts. Überprüfen Sie vor dem Drucken im Destruktor, ob gerade eine Exception gerade im Fluge ist, was mit std::uncaught_exception (in C++ 17 wird std::uncaught_exceptions) erfolgen kann.


Wenn etwas flexibler benötigt wird, können Sie einen Wrapper für Ihren Rückgabewert verwenden, ist es für void spezialisiert:

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 führen den Funktionsaufruf und speichert das Ergebnis, das später sein ausgezogen über value(). Dies steht mit der Möglichkeit, einen void -Typ Ausdrucks von einer void Funktion der Rückkehr:

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

Vielen Dank für Vorschlag. Habe noch nie von std :: uncaught_exception gehört. Der einzige Nachteil ist, dass die Überprüfung in der Laufzeit durchgeführt wird und ich dafür eine Leistungseinbuße zahlen muss – sliser

Verwandte Themen