RAII template for receiving / issuing with variable templates

I am trying to replace all my RAII Acquisition / Release classes (I have one for each type of resource at the moment) with one template. The general form of acquisition is that some types are Acquire (), some are Acquire (p1), some are Acquire (p1, p2), etc. The same applies to Release. But if a resource is acquired with parameters, it must be released with the same parameters.

I think I can do this with variable templates, storing the arguments in a tuple. Of course, I fell for the syntax. Can anyone help?

#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; } 
+5
source share
2 answers

Apart from a few minor things, such as pointer and value discrepancies, your main problems are that you cannot reference Raii without template arguments, and you are not expanding the parameter / parameter parameter package.

Here is a working version that you could improve with additional sprinkles of perfect forwarding, etc.

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

Live demo

+3
source

I'm sure the magic will be:

 subject->Acquire(a...); 

Since a is a template package, you need to deploy it to call.

To extend a tuple into a variable call, an integer_sequence extension is required.

+1
source

Source: https://habr.com/ru/post/1232183/


All Articles