【问题标题】:Is it possible to detect if a function is called at compile time是否可以检测是否在编译时调用了函数
【发布时间】:2022-01-12 07:09:19
【问题描述】:

我正在开发一个 C++ 库,有两个函数:func1func2

如果开发人员在调用func2 之前忘记调用func1,我想生成一个编译时错误:

这样就可以了:

func1();
func2();  // OK

但这会失败:

func2();  // ERROR, you forget to call func1()

当然,很容易产生运行时错误,但我想产生一个编译时错误。

我已经尝试如下,但它不起作用,因为我无法修改 constexpr 变量:

static constexpr bool b {false};

void func1() {
    b = true; // ERROR!
}

typename<std::enable_if_t<b == true>* = nullptr>
void func2() {}

我不太擅长元编程。我想知道在这种情况下是否有可能产生编译时错误。

【问题讨论】:

  • 我不明白为什么人们一直在寻找语言解决方案来设计气味。如果功能如此耦合,为什么它们是分开的?
  • 查看 constexpr 计数器是如何制作的(例如 this one)。第一个函数实例化一个包含友元函数定义的模板类,第二个函数检查该友元函数是否存在。
  • 安顿下来,伙计。 StoryTeller 在这里提出的观点是,有一些真正的方法可以使用实际的语言结构来解决问题。您提出问题的方式是 XY 问题。
  • 不,我们没有,老兄。参数化构造函数和单例已经使用了几十年,尽管外行人坚持反对。
  • 这绝对是XY问题。在调用func2() 之前,您需要至少调用一次func1(),并相信让编译器诊断此类情况是解决方案。编译器不能做这样的事情,特别是如果func1()func2() 以及调用它们中的任何一个的函数位于不同的源文件中。相反,您需要重新设计func2(),以便它调用func1(),并在必要时跟踪它这样做的事实(这样可以避免在需要时再次调用func1())。更好的是,不要将func1() 提供给其他代码。

标签: c++ templates metaprogramming enable-if


【解决方案1】:

明确时间耦合:

  • 使func1 返回一个应该被func2 使用的类型:
struct func1_result {
// Possibly constructors private, and friendship to `func1`.
//...
};

func1_result func1();
void func2(const func1_result&);

因此,如果不创建第一个 func1_result(由 func1 返回),就不能调用 func2

【讨论】:

  • 这个问题是没有什么能阻止另一个函数被定义为const func1_result &amp;foo() {}。然后func2(foo()) 将导致不诊断,即使func1() 从未被调用。更糟糕的是,foo() 会导致不需要诊断的未定义行为 - 实际上,这通常意味着程序将在没有诊断的情况下编译和链接。
  • @Peter:const func1_result &amp;foo() {} 本身就是 UB,编译器会警告该构造具有适当的级别。 “C++ 试图防范墨菲,而不是马基雅维利。”
  • 两个公平点。可以通过使结果类具有公共复制/赋值语义但私有构造并成为func1 的朋友,然后将其按值传递给func2 来解决。获得可以复制的值的唯一方法是调用唯一可以创建它的东西。我在需要时使用这种方法。
【解决方案2】:

至少在极端情况下是不可能的。看下面的代码(为了简洁省略了scanf返回值的标题和测试):

int main() {
    int code;
    printf("Enter code value: ");
    scanf("%d", &code);
    if (code > 0) func1();
    func2();               // has func1 be called ?
    return 0;
}

在这里,即使是最好的静态分析工具也无法说明是否在func2 之前调用了func1,因为它取决于一个仅在运行时才知道的值。好吧,这是一个相当愚蠢的例子,但现实世界的程序经常在运行时读取它们的配置数据,并且该配置甚至可以改变它们的部分初始化。

【讨论】:

  • 嗯...我知道你的意思。现在我在考虑编译时计数器是否可以提供帮助......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 1970-01-01
相关资源
最近更新 更多