Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get rid of the manual class template parameter specification

Tags:

c++

c++11

lambda

Is there any more generic way to write a Finalizer class than this?

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

I want to get rid of the manual class template parameter specification to be able to write code like this:

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

Is it possible?

like image 587
FrozenHeart Avatar asked Mar 10 '16 09:03

FrozenHeart


1 Answers

In C++ type deduction is only available for function templates, not for class templates. You need a make_finalizer function to perform template argument deduction.

Also you don't have to use std::function at all, no need to pay for the runtime cost, unless you actually want it to be type-erased.

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

And use it with auto:

 auto x = at_scope_exit([]() { std::cout << "Hello world" << std::endl; });
like image 126
sbabbi Avatar answered Sep 24 '22 18:09

sbabbi