You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为同一函数实例创建相同静态变量,不同实例创建不同变量?

问题

我需要监听多个时间序列的变化,因此产生了大量如下重复代码:

/* ------------- 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:52:57