#include <iostream>
#include <tuple>

struct Result
{
    Result() : m_success(true) {}
    explicit operator bool() const { return !m_success; }
    bool m_success;
};

template<unsigned index, typename... Types>
struct TupleItemDeleter
{
    void operator() (std::tuple<Types...>& t)
    {
        std::cout << "Deleting item at index " << index << std::endl;
        delete std::get<index>(t);
        TupleItemDeleter<index - 1, Types...>{}(t);
    }
};

template<typename... Types>
struct TupleItemDeleter<0, Types...> 
{
    void operator() (std::tuple<Types...>& t)
    {
        std::cout << "Deleting item at index 0" << std::endl;
        delete std::get<0>(t);
    }
};

template<typename... Types>
void deleter(std::tuple<Types...>& t)
{
    constexpr auto tupleSize = std::tuple_size<std::tuple<Types...>>::value;
    TupleItemDeleter<tupleSize - 1, Types...>{}(t);
}


template<typename... T>
struct CleanupHelper {

    CleanupHelper (const Result& res, const std::tuple<T...>& itemsToDelete)
     : m_result(res)
     , m_itemsToDelete(itemsToDelete)
    {
    }

    ~CleanupHelper()
    {
        if(!m_result)
        {
           deleter(m_itemsToDelete);
        }
    }
    
    const Result& m_result;
    std::tuple<T...> m_itemsToDelete;
};

struct Foo {};

Result functionThatNeedsCleanup()
{
	Result res;
	Foo *pFoos_1, *pFoos_2;
	CleanupHelper<Foo*,Foo*> cleanupHelper(res, std::make_tuple(pFoos_1, pFoos_2));
	try
	{
		pFoos_1 = new Foo;
		pFoos_2 = new Foo[10];
		//
		// Do work
		//
	}
	catch(...)
	{
		res.m_success = false;
	}
}

int main()
{
  functionThatNeedsCleanup();
  return 0;
}