2015-09-24 33 views
5

Sto tentando di sostituire tutte le mie classi RAII "Acquire/Release" (ne ho una per ogni tipo di risorsa al momento) con una sola classe basata su modelli. La forma generale di acquisizione è che alcuni tipi sono Acquire(), alcuni sono Acquisisci (p1), alcuni sono Acquisisci (p1, p2), ecc. Lo stesso è vero per il Release. Ma se una risorsa è acquisita con parametri, allora deve essere rilasciata con quegli stessi parametri.Modello RAII per acquisizione/rilascio con modelli variadici

Penso di poterlo fare con i modelli variadic, memorizzando gli argomenti in una tupla. Ovviamente sono caduto nella sintassi. Qualcuno può aiutare?

#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; 
} 
+0

possibile duplicato del [mascherina mascherine variadic e spedizioni perfetta] (http: // StackOverflow .com/questions/6486432/variadic-template-templates-and-perfect-forwarding) –

+0

Fa touch su forwarding perfetto ma questo è un esempio pratico, molto più semplice di quello che è descritto su quel thread. Quindi voto di non chiudere, almeno finché non funziona. – Robinson

risposta

3

A parte alcune piccole cose come le discrepanze puntatore/valore, i problemi principali sono che non è possibile fare riferimento a Raii senza argomenti del modello e non si espande il parametro parameter pack/tuple.

Ecco una versione di lavoro che si potrebbe migliorare con alcuni spruzzi extra di inoltro perfetta ecc

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

+0

Interessante, non sapevo che 'index_sequence' lo avesse trasformato in C++ 14. Buona risposta. –

+0

Sì, ho risolto il problema del puntatore/valore. Sfortunatamente ho C++ 11 quindi no index_sequence. Ho trovato un'implementazione C++ 11 su github, quindi potrei usarlo. https://gist.github.com/doicanhden/7249956, sebbene questa implementazione in realtà mi dia "errore fatale C1001: si è verificato un errore interno nel compilatore" (Visual Studio 2013). – Robinson

+0

@Robinson Yay, bug del compilatore. Sembra [funziona bene] (http://coliru.stacked-crooked.com/a/c95f162cd89dbfd7) in Clang. Vedrò se riesco a trovare uno compatibile con VS2013. – TartanLlama

1

Sono piuttosto sicuro che la magia sarebbe:

subject->Acquire(a...); 

Dal a è un pacchetto modello, è necessario espanderla per la chiamata.

L'espansione di una tupla in una chiamata variadica richiede integer_sequence expansion.

+0

Ahah! Anche se dice "l'uso della classe richiede l'elenco degli argomenti del modello" (dove sto istanziando gli oggetti Raii). Perché non può dedurre l'elenco degli argomenti del modello dai parametri del costruttore? – Robinson

+0

@Robinson perché C++. Usa una funzione di aiuto ('make_raii'). Questo è lo stesso problema che si verifica con 'make_tuple' e' make_pair' ecc. –

Problemi correlati