2016-03-10 7 views
5

Finalizerクラスをこれよりも一般的な方法で書くことはできますか?手動クラステンプレートのパラメータ指定を取り除く方法

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

私はこのようなコードを書くことができるように手動でクラスのテンプレートパラメータの指定を取り除きたい:

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

それは可能ですか?

+0

?あるいは、デフォルトのテンプレートパラメータ 'typename T = void()'を与えますか? – Garf365

+0

@ Garf365より一般的にする。いくつかのファイナライザメソッドは実際にはエラーコードを返すことができる別個の関数ですが、私は 'Finalizer'クラスでそれらをそのまま使用し、そのような状況ではエラーコードを無視したいと考えています – FrozenHeart

+0

@FrozenHeart' std :: function '結果、問題はない。 – lisyarus

答えて

5

C++型の控除は、関数テンプレートでのみ使用でき、クラステンプレートでは使用できません。 テンプレート引数の控除を実行するには、make_finalizer関数が必要です。

また、std::functionをまったく使用する必要はありません。実際にタイプ消去しない限り、ランタイムコストを支払う必要はありません。

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

と自動でそれを使用します。直接 `のstd ::機能 `を書いていないのはなぜ

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

なぜ 'std :: forward'コールが必要なのですか? – FrozenHeart

+0

@FrozenHeartラムダを移動するのではなく、 'Finalizer'の中にコピーしたいかもしれないからです。 – sbabbi

関連する問題