如何为同一函数实例创建相同静态变量,不同实例创建不同变量?
问题
我需要监听多个时间序列的变化,因此产生了大量如下重复代码:
/* ------------- 1 -------------- */ int a = my_random_nr(); static int a_last; if(a != a_last) {/*do something*/}; a_last = a; /* ------------- 2 -------------- */ double b = my_random_nr(); static double b_last; if(b != b_last) { /*do something*/ }; b_last = b; /* ------------- 3 -------------- */ string c = my_random_nr(); static string c_last; if(c != c_last) { /*do something*/ }; c_last = c;
我无法直接编写可复用函数实现该逻辑,因为函数内的static <datatype> last变量会被所有实例共享,造成干扰。
在C及其衍生语言MQL5中,默认无法为每个函数实例动态创建专属静态变量,但可通过C的##预处理操作符尝试实现。为简化为单行代码(如if( isNew<int>(my_random_nr) ) { /*do something*/ };),我编写了如下代码:
/* --------------- (1/2) ## preprocessing operator ---------------- */ #define UniqueVar(nr) last##nr /* -------------- (2/2) The 'normal' function itself --------------- */ template <typename T> // #define UniqueVar(nr) last##nr → // #define UniqueVar(nr) last##nr → bool isNew(T var) // SHOULD (e.g. 1st function instance): // IS (e.g. 1st function instance): { static T UniqueVar(__COUNTER__); // last0 // last0 bool is_new; if(var != UniqueVar(__COUNTER__)) is_new = true; // last0 // last1 else is_new = false; UniqueVar(__COUNTER__) = var; // last0 // last2 return is_new; };
但第一个函数实例未如预期始终创建last0,而是生成last0、last1、last2等不同变量。尝试先存储__COUNTER__值再使用,会导致所有实例共用lastunique_ID,此方法无效。
请问如何实现:为同一函数实例始终创建相同静态变量,仅为不同实例创建不同静态变量?
解决方案
方法1:模板+标签类型区分实例
通过定义空的标签结构体,让每个调用点绑定不同的标签,模板会为每个「类型+标签」组合生成独立的函数实例,各自拥有专属静态变量:
// 定义独立的空标签结构体,每个时间序列对应一个标签 struct TimeSeriesTag1 {}; struct TimeSeriesTag2 {}; struct TimeSeriesTag3 {}; template <typename T, typename Tag> bool isNew(T var) { static T last; bool is_new = (var != last); last = var; return is_new; } // 调用示例 if(isNew<int, TimeSeriesTag1>(my_random_nr())) { /* 处理int序列变化 */ } if(isNew<double, TimeSeriesTag2>(my_random_nr())) { /* 处理double序列变化 */ } if(isNew<string, TimeSeriesTag3>(my_random_nr())) { /* 处理string序列变化 */ }
方法2:宏结合__COUNTER__生成唯一静态变量
利用__COUNTER__的递增特性,为每个宏调用生成唯一的静态变量名,确保同一调用点复用同一个变量:
// 内部实现宏,接收变量和计数器值 #define IS_NEW_IMPL(var, cnt) [&]() { \ static decltype(var) last##cnt; \ bool is_new = (var != last##cnt); \ last##cnt = var; \ return is_new; \ }() // 对外暴露的宏,自动传入递增的计数器 #define IS_NEW(var) IS_NEW_IMPL(var, __COUNTER__) // 调用示例 int a = my_random_nr(); if(IS_NEW(a)) { /* 处理变化 */ } double b = my_random_nr(); if(IS_NEW(b)) { /* 处理变化 */ } string c = my_random_nr(); if(IS_NEW(c)) { /* 处理变化 */ }
如果MQL5不支持lambda,可以改用普通函数宏:
#define IS_NEW(var, cnt) \ static decltype(var) last##cnt; \ bool is_new_##cnt = (var != last##cnt); \ last##cnt = var; \ is_new_##cnt // 调用时手动指定唯一标识(比如行号或自定义编号) int a = my_random_nr(); if(IS_NEW(a, 1)) { /* 处理变化 */ } double b = my_random_nr(); if(IS_NEW(b, 2)) { /* 处理变化 */ }
方法3:带状态的检测器实例(兼容MQL5)
手动创建每个时间序列对应的检测器实例,每个实例维护独立的状态变量,逻辑直观且兼容性强:
template <typename T> struct ChangeDetector { T last; bool operator()(T var) { bool is_new = (var != last); last = var; return is_new; } }; // 为每个时间序列定义独立的检测器 ChangeDetector<int> detectorInt; ChangeDetector<double> detectorDouble; ChangeDetector<string> detectorString; // 调用示例 int a = my_random_nr(); if(detectorInt(a)) { /* 处理变化 */ } double b = my_random_nr(); if(detectorDouble(b)) { /* 处理变化 */ } string c = my_random_nr(); if(detectorString(c)) { /* 处理变化 */ }
内容的提问来源于stack exchange,提问作者TantoMano
相关产品推荐
相关产品推荐

