如何在变量超出作用域时重置多个变量?
多变量作用域退出时自动重置的实现方案
你已经实现了单变量的栈式自动重置逻辑,现在要扩展到多变量版本,下面针对你的疑问逐一给出实现方案:
原单变量实现代码
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)
1. 成员变量ref的类型
不能用单一的T&,因为要存储多个不同类型变量的引用,应该使用std::tuple<Ts&...>作为引用容器,这样可以保存任意数量、任意类型的变量引用。
2. 构造函数实现
构造函数需要接收所有待保存变量的引用,同时把每个变量的当前值存入savedValues(std::tuple<Ts...>类型),并把变量引用存入ref成员:
template<typename... Ts> struct Context { std::tuple<Ts...> savedValues; std::tuple<Ts&...> refs; // 构造函数:接收变量引用,保存原始值和引用 Context(Ts&... vars) : savedValues(vars...), // 拷贝每个变量的当前值到savedValues refs(vars...) // 保存每个变量的引用 {}
3. 析构函数的重置逻辑
需要遍历tuple的每个元素,将savedValues中保存的原始值赋值给refs中对应的变量引用。利用C++14的std::index_sequence实现编译期遍历:
private: // 辅助函数:通过索引序列逐个赋值 template<std::size_t... Is> void reset(std::index_sequence<Is...>) { // 折叠表达式:对每个索引Is,执行赋值操作 (std::get<Is>(refs) = std::get<Is>(savedValues), ...); } public: ~Context() { // 生成对应长度的索引序列,调用重置函数 reset(std::index_sequence_for<Ts...>{}); } };
4. 宏定义编写
支持可变参数,同时生成唯一的实例名(避免同作用域内重复定义),模板会自动推导每个变量的类型:
#define CONCAT_(x,y) x##y #define CONCAT(x,y) CONCAT_(x,y) #define SAVE_CONTEXT(...) Context CONCAT(ctx, __LINE__)(__VA_ARGS__)
完整代码与使用示例
#include <tuple> #include <utility> // 用于std::index_sequence #include <string> template<typename... Ts> struct Context { std::tuple<Ts...> savedValues; std::tuple<Ts&...> refs; Context(Ts&... vars) : savedValues(vars...), refs(vars...) {} private: template<std::size_t... Is> void reset(std::index_sequence<Is...>) { (std::get<Is>(refs) = std::get<Is>(savedValues), ...); } public: ~Context() { reset(std::index_sequence_for<Ts...>{}); } }; #define CONCAT_(x,y) x##y #define CONCAT(x,y) CONCAT_(x,y) #define SAVE_CONTEXT(...) Context CONCAT(ctx, __LINE__)(__VA_ARGS__) // 使用示例 int main() { int a = 1; double b = 2.5; std::string c = "hello"; { SAVE_CONTEXT(a, b, c); // 保存当前值 a = 100; b = 3.14; c = "modified"; // 此处变量已被修改 } // 作用域退出后,a、b、c自动恢复为原始值:1, 2.5, "hello" return 0; }
内容的提问来源于stack exchange,提问作者user765269
相关产品推荐
相关产品推荐

