2016-03-10 12 views
5

Esiste un modo più generico per scrivere una classe Finalizer rispetto a questa?Come eliminare la specifica del parametro del modello di classe manuale

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

voglio sbarazzarsi della specifica manuale dei parametri di modello di classe per essere in grado di scrivere codice come questo:

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

E 'possibile?

+0

Perché non scrivere direttamente 'std :: funzione '? Oppure fornire un parametro template predefinito 'typename T = void()'? – Garf365

+0

@ Garf365 per essere più generico. Alcuni metodi di finalizzazione possono in realtà essere funzioni separate che possono restituire codici di errore, ma voglio usarli comunque nella classe 'Finalizer' e ignorare i loro codici di errore in tali situazioni – FrozenHeart

+0

@FrozenHeart L'uso di' std :: function 'verrà automaticamente ignorato il risultato, nessun problema qui. – lisyarus

risposta

5

In deduzione di tipo C++ è disponibile solo per i modelli di funzione, non per i modelli di classe. È necessaria una funzione make_finalizer per eseguire la deduzione degli argomenti del modello.

Inoltre non è necessario utilizzare std::function, non è necessario pagare il costo di runtime, a meno che non si desideri cancellarlo.

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

e utilizzarlo con auto:

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

Perché ho bisogno della chiamata 'std :: forward' qui? – FrozenHeart

+0

@FrozenHeart perché potresti voler copiare il lambda all'interno di 'Finalizer' invece di spostarlo. – sbabbi

Problemi correlati