1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
// Une classe generique de push_back transactionnels sur un nombre quelconque
// de conteneurs
// parametres:
// - Container: une classe de conteneur (qui doit gerer push_back()/pop_back()
// - ContainerCount: le nombre de conteneur a gerer.
template <class Container, size_t ContainerCount>
class SafeTransaction
{
// nos conteneurs internes.
Container m_containers[ContainerCount];
// Insere des elements dans des conteneurs, de maniere recursive.
// parametres:
// - index: index du conteneur dans le tableau m_conteneur qui va etre modifie.
// - value: valeur a inserer
// - values: reste des arguments...
template<typename T, typename... Ts>
void push_back_impl(int index, T value, Ts... values)
{
// A-t-on bien ajoute l'element ?
bool done = false;
try
{
// on insere l'argument en cours dans le bon conteneur
m_containers[index].push_back(value);
done = true;
// s'il reste des arguments, on le transfere au template recursif suivant.
if (sizeof...(values) > 0)
{
push_back_impl(index+1, values...);
}
}
catch (...)
{
// en cas d'erreur, on enleve le dernier element du conteneur et on
// propage l'exception a l'appelant.
if (done)
{
m_containers[index].pop_back();
}
throw;
}
}
public:
// methode visible permettant d'insérer des elements dans un nombre quelconque de
// conteneurs. Le premier argument est inséré dans le premier conteneur, le
// deuxième argument dans le deuxieme conteneur, et ainsi de suite..
template<typename... Ts>
void push_back(Ts... parameters)
{
static_assert(sizeof...(parameters) <= ContainerCount, "Too many arguments.");
if (sizeof...(parameters) > 0)
{
push_back_impl(0, parameters...);
}
}
}; |
Partager