Search code examples
c++templatesscopec++17class-template

How to reset multiple variables when going out of scope?


I want to reset multiple variables when they go out of scope.

Currently, I have a solution for 1 variable, which is similar to given in the answers here:

General way to reset a member variable to its original value using the stack?

template<typename T>
struct Context
{
    T savedValue;
    T& ref;
    Context(T& value) : savedValue(value), ref(value) {}

    ~Context()
    {
        ref = savedValue;
    }
};
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
// __line__ to allow multiple
#define SAVE_CONTEXT(var) Context<decltype(var)> CONCAT(ctx, __LINE__)(var)   

What I am looking for is something like this:

template<typename... Ts>
struct Context
{
    std::tuple<Ts...> savedValues;  // OK
    T& ref;                         // What should be the type here?
    Context(Ts... values) : {}      // How ?

    ~Context()
    {
        // ?
    }
};
#define SAVE_CONTEXT(...) ...       // ?

Solution

  • If I understood the issue correctly, you could achieve the same with non-MACRO ways.

    #include <tuple>
    #include <utility>
    
    template<typename... Args> class Context
    {
       std::tuple<Args...> mSavedValues; // for values
       std::tuple<Args&...> mRefs;       // for references
    
    public:
       constexpr Context(Args&... values)
           : mSavedValues(values...)
           , mRefs(values...)
       {}
    
       constexpr ~Context() {
           // reset to the initial values
           mRefs = mSavedValues;
       }
    };
    
    // template "saveContext" instead of the MACRO
    template<typename... Args>
    constexpr Context<Args...> saveContext(Args&... values) {
       return Context<Args...>(values...);
    }
    

    You would use it like this:

    int main()
    {
        int a = 1;
        float b = 2.2f;
        {
            auto ctx = saveContext(a, b);
            a = 10;
            b = 20.02f;
            // a and b will be set to 10 and 20.02f
        }
        // a and b will be reset to their original values 
        // (1 and 2.2f) when going out of scope
    }
    

    See a live demo in godbolt.org