2016-03-10 5 views
5

loswird Gibt es eine allgemeinere Weise, eine Finalizer Klasse als diese zu schreiben?Wie man die manuelle Klassenschablonen-Parameterspezifikation

#include <functional> 
#include <iostream> 

template <typename T> 
class Finalizer 
{ 
public: 
    Finalizer(const std::function<T>& f) : _f(f) {} 

    ~Finalizer() 
    { 
     _f(); 
    } 

private: 
    std::function<T> _f; 
}; 

int main() 
{ 
    Finalizer<void()> finalizer([]() { std::cout << "str" << std::endl; }); 
} 

Ich möchte der manuellen Klasse Template-Parameter-Spezifikation, um loszuwerden, der Lage sein, Code wie folgt zu schreiben:

Finalizer finalizer([]() { std::cout << "str" << std::endl; }); 

Ist es möglich?

+0

Warum nicht direkt 'std :: function ' zu schreiben? Oder geben Sie einen Standard-Template-Parameter 'typename T = void()'? – Garf365

+0

@ Garf365 Um allgemeiner zu sein. Einige Finalizer-Methoden können eigentlich separate Funktionen sein, die Fehlercodes zurückgeben können, aber ich möchte sie trotzdem in der 'Finalizer'-Klasse verwenden und ihre Fehlercodes ignorieren – FrozenHeart

+0

@FrozenHeart Die Verwendung von 'std :: function ' wird automatisch ignoriert Das Ergebnis, hier kein Problem. – lisyarus

Antwort

5

In C++ Typ Abzug ist nur für Funktionsvorlagen verfügbar, nicht für Klassenvorlagen. Sie benötigen eine make_finalizer-Funktion, um die Vorlageargumentableitung durchzuführen.

Sie müssen auch std::function überhaupt nicht verwenden, keine Notwendigkeit für die Laufzeitkosten zu bezahlen, es sei denn, Sie möchten es tatsächlich gelöscht werden.

template <typename F> 
class Finalizer 
{ 
public: 
    Finalizer(const F & c) : f_(c) {} 
    Finalizer(F && c) : f_(std::move(c)) {} 
    Finalizer(const Finalizer &) = delete; 
    Finalizer(Finalizer && other) : 
      valid_(other.valid), 
      f_(std::move(other.f_)) 
    { 
     other.valid_ = false; 
    } 

    Finalizer& operator=(const Finalizer &) = delete; 
    Finalizer& operator=(Finalizer && other) 
    { 
     Finalizer tmp(std::move(other)); 
     swap(tmp); 
     return *this; 
    } 

    ~Finalizer() 
    { 
     if (valid_) 
      f_(); 
    } 

    void swap(Finalizer & other) noexcept 
    { 
     using std::swap; 
     swap(other.valid_, valid_); 
     swap(other.f_, f_); 
    } 

private: 
    bool valid_ = true; 
    F f_; 
}; 

template<class F> 
Finalizer< std::remove_reference_t<F> > at_scope_exit(F && x) 
{ 
    return Finalizer< std::remove_reference_t<F> >(std::forward<F>(x)); 
} 

Und mit Auto verwenden:

auto x = at_scope_exit([]() { std::cout << "Hello world" << std::endl; }); 
+0

Warum brauche ich hier 'std :: forward'? – FrozenHeart

+0

@FrozenHeart, weil Sie vielleicht das Lambda innerhalb des Finalizers kopieren möchten, anstatt es zu verschieben. – sbabbi