基于构造函数的存在禁用代码

Disable code based on existence of Constructor

我试图根据代码是否创建对象(或调用函数或其他)来禁用某些代码。听起来有点奇怪,我知道。

在我的库中可以创建 2 个对象,每个对象都需要一个中断服务例程,例如:

ISR(TIMER0_COMPA_vect) {
  // do some stuff if the interrupt happens
}

ISR 只能创建一次,但用户可能只创建一个或 none 我的对象,因此不应首先创建 ISR,以免阻止创建一个由用户。 我知道像这样封装代码会很容易

#ifdef OBJECT1
  ISR(TIMER0_COMPA_vect) {
    // do some stuff if the interrupt happens
  }
#endif

但这会强制用户跟踪创建的对象 she/he。 是否有一个选项可以让预处理器决定构造函数是否被调用一次甚至存在? 有点像这样

Foo:Foo() {
  #define USE_FOO
  //Some code
}

#ifdef USE_FOO
ISR(TIMER0_COMPA_vect) {
  // do some stuff if the interrupt happens
}
#endif

编辑:

根据我得到的答案,我试着澄清一下我的问题:

Foo1:Foo1() {
    //Some object constructor code
}

Foo2:Foo2() {
    //Some object constructor code
}

ISR(TIMER1_COMPA_vect) {
    //some interrupt code
}

ISR(TIMER2_COMPA_vect) {
    //some interrupt code
}

int main() {
    Foo2 foo2;
}

如果这是我们正在谈论的代码,则根本不应编译函数 ISR(TIMER1_COMPA_vect)。 ISR 必须不存在。

PS:如果您需要更多信息,我可以提供更多,但我尽量让问题尽可能简单

正如您所说,您的问题听起来很奇怪,但是如果您只想在构造函数中做某事一次,那么您可以使用局部静态变量来做一个简单但非常丑陋的事情

Foo:Foo() {
  static bool init = true;
  if( init ) {
    //Some code for ISR init
    init = false;
  }
}

这样,无论您或您的用户构建了多少个 Foo 对象,您的特殊 ISR 初始化都只会发生一次

编辑:

我认为没有办法实现你想要的,至少没有干净的方法。

我想你的问题来自你的 ISR 宏,它实际上做了两件事:

  • 正在初始化您的 ISR 向量(ISR 注册)
  • 正在定义您的 ISR 处理程序(ISR 处理程序)

为了解决您的问题,我建议您将其拆分为两个宏:

  • ISR 注册进入 Foo1 / Foo2 构造函数 -> 使用全局字段或任何机制仅初始化一次或在内部跟踪发生的事情等
  • 保留另一个只有处理程序定义的宏 ISR_HANDLER

你的处理程序可以保持定义,如果它没有被任何 Foo 注册,应该没有影响 类

您可能需要创建单例。有很多例子。单例是 class 构造自身,仅一次。构造函数是私有的,静态方法检查 "global" 变量以查看 class 是否已经构造,如果没有构造它自己只会构造一次。您可能需要考虑线程问题,尽管对于构建,您可以在创建多个 class 之前简单地引用 class。对于一个中断的多个用户,您通常使用对象注册的某种调度程序,然后调用所有对中断感兴趣的 classes。调度员可能是单身人士。通常,调度程序的客户端实现一个接口。作为向调度程序注册的一部分,class 告诉调度程序它的 "this" 指针,调度程序可以调用从接口实现的方法,就好像它们被正常调用一样。客户端不需要有静态方法。这些东西可能有模式,但我不能说出任何模式。

对于这种情况,您通常会做的是将此类对象的代码编译到库中。链接器足够智能,可以检测您的主程序是否依赖库中的任何函数。如果是,它将将该函数的整个编译单元(即 .c 或 .cpp 文件)加载到您的程序中。它在编译单元中找到的任何 ISR 都将添加到您的程序中。如果您不使用库中的任何函数,则不会添加 ISR。

例如,在foo1.h中放入这样的内容:

#pragma once
class Foo1 {
public:
  Foo1();
};

在 foo1.cpp 中放入这样的内容:

#include <foo1.h>

ISR(TIMER1_COMPA_vect) {
}

Foo1::Foo1() {
}

现在您应该使用 avr-gccfoo1.cpp 编译成 foo1.o。接下来,使用 avr-arfoo1.o 存储在名为 foo1.a 的存档中。然后,使用 avr-gcc 编译主程序,并提供 foo1.a 作为参数。确保 foo1.a 参数出现在 main.cpp.

之后