2016-03-10 15 views
5

Có cách nào chung chung hơn để viết lớp Finalizer không?Làm cách nào để loại bỏ đặc tả tham số mẫu lớp thủ công

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

Tôi muốn thoát khỏi hướng dẫn lớp mẫu đặc tả tham số để có thể viết mã như thế này:

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

Có thể?

+0

Tại sao không viết trực tiếp 'std :: chức năng '? Hoặc đưa ra một tham số mẫu mặc định 'typename T = void()'? – Garf365

+0

@ Garf365 Để trở nên chung chung hơn. Một số phương thức finalizer có thể thực sự là một hàm riêng biệt có thể trả về mã lỗi nhưng tôi muốn sử dụng chúng trong lớp 'Finalizer' và bỏ qua mã lỗi của chúng trong các tình huống như vậy – FrozenHeart

+0

@FrozenHeart Sử dụng' std :: function 'sẽ tự động bỏ qua kết quả, không có vấn đề ở đây. – lisyarus

Trả lời

5

Trong khấu trừ loại C++ chỉ có sẵn cho mẫu chức năng, không áp dụng cho mẫu lớp. Bạn cần có một hàm make_finalizer để thực hiện khấu trừ đối số mẫu.

Ngoài ra, bạn không phải sử dụng std::function chút nào, không cần phải trả chi phí thời gian chạy, trừ khi bạn thực sự muốn nó bị xóa.

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

Và sử dụng nó với ô tô:

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

Tại sao tôi cần lệnh gọi 'std :: forward' ở đây? – FrozenHeart

+0

@FrozenHeart vì bạn có thể muốn sao chép lambda bên trong 'Finalizer' thay vì di chuyển nó. – sbabbi

Các vấn đề liên quan