使用可变参数模板获取/释放的RAII模式

Rob*_*son 5 c++ raii variadic-templates

我试图用一个模板化的类来替换我的所有"获取/发布"RAII类(我现在每种资源都有一个).获取的一般形式是一些类型是Acquire(),一些是Acquire(p1),一些是Acquire(p1,p2)等.Release也是如此.但是,如果资源是使用参数获取的,则需要使用相同的参数释放它.

我想我可以使用可变参数模板,将参数存储在元组中.当然,我已经贬低了语法.有人可以帮忙吗?

#include <tuple>

template<class T, typename... Args>
class Raii
{
public:

    Raii(T * s, Args&& ... a) : subect(s), arguments(a)
    {
        subject->Acquire(arguments);
    }

    ~Raii()
    {
        subject->Release(arguments);
    }

private:

    T subject;
    std::tuple<Args...> arguments;
};

class Framebuffer
{
public:

    void Acquire() {}
    void Release() {}
};

class Sampler
{
public:

    void Acquire(int channel) {}
    void Release(int channel) {}
};

class Buffer
{
public:

    void Acquire(int target, int location) {}
    void Release(int target, int location) {}
};

int main(void)
{
    Framebuffer f;
    Sampler s;
    Buffer b;

    auto b1 = Raii(&f);
    {
        auto b2 = Raii(&s, 10);
        {
            auto b3 = Raii(&b, 10, 20);
            {

            }
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Tar*_*ama 3

除了一些小问题(例如指针/值差异)之外,您的主要问题是您无法在Raii没有模板参数的情况下引用,并且无法扩展参数参数包/元组。

这是一个工作版本,您可以通过一些额外的完美转发等改进。

template<class T, typename... Args>
class Raii
{
public:

    Raii(T & s, Args&& ... a) : subject(s), arguments(a...)
    {
        //expand a
        subject.Acquire(a...);
    }

    //helper to expand tuple
    //requires std::index_sequence and friends from C++14
    //if you are limited to C++11, you can find implementations online
    template <std::size_t... Idx>
    void release(std::index_sequence<Idx...>) 
    {
        subject.Release(std::get<Idx>(arguments)...);
    }

    ~Raii()
    {
        //yay, index trick
        release(std::index_sequence_for<Args...>{});
    }

private:

    T &subject;
    std::tuple<Args...> arguments;
};

//helper function so that we can deduce the Raii template args
template <class T, typename... Args>
Raii<T,Args...> make_raii (T & t, Args&&... args) {
    return {t, std::forward<Args>(args)...};   
}

// Framebuffer etc.

int main()
{
    Framebuffer f;
    Sampler s;
    Buffer b;

    //use make_raii instead of Raii
    auto b1 = make_raii(f);
    {
        auto b2 = make_raii(s, 10);
        {
            auto b3 = make_raii(b, 10, 20);
            {

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Live Demo