【问题标题】:How to leave a declared function undefined in C++ like with `undefined` in Haskell?如何在 C++ 中保留未定义的已声明函数,例如 Haskell 中的“未定义”?
【发布时间】:2024-01-08 10:37:01
【问题描述】:

在 Haskell 中有一个名为 undefined 的常量,您可以使用它 声明一个函数而不定义它(即一个空主体的函数原型),就像squarein

square :: Int -> Int   -- declaration
square = undefined     -- empty definition

main = putStrLn.show.square $ 3

这对于推迟 square 的工作并首先专注于正确获取 main 函数非常有用,因为 Haskell 编译器确保整个文件编译时就像定义了 square 一样。

C++ 等价物是

#import <iostream>
int square(int x){
  //TODO incomplete
  return 0;
}

int main() {
  std::cout << square(3);
}

我的意图是调用像clang++ 这样的编译器作为main 的类型检查器,然后再处理square。想象一下,square 确实是许多尚未定义的复杂函数之一,它们返回具有非平凡构造函数的复杂数据结构。我必须编写大量代码来创建可返回对象,只是为了编译函数。

在 C++ 中是否存在类似于 undefined 的简单粗暴的东西?

【问题讨论】:

  • 链接器是编译后的一步。当您收到该错误时,您的代码已经通过了编译器的类型检查。
  • 有什么你想在这里实现的,因为这是一个微不足道的例子,你的真实案例可能不需要这个就可以解决
  • 我并没有真正看到它的用途,你可以暂时给它一个空定义,但如果你想要类似的行为(例如崩溃),你可以使用一个宏来定义类似这样的东西:#define UNDEFINED{_ASSERT(0)},然后在你的函数声明之后使用它,但正如@EdChum 提到的,可能有更好的方法来解决你的实际问题
  • undefined 对严格的语义没有那么有用。如果你只是想避免定义一个函数,给它一个{ throw "undefined"; } body。
  • @xEric_xD undefined 的一个用途是编译器会告诉你它期望在你使用过undefined 的地方是什么类型,这在像someGenericLibraryFn (someAbstractHelper undefined) 42 这样的调用中通常非常有用,其中类型函数的签名可能有点长,您只想查看类型签名的 那一部分。我不知道@mahene 是否希望从 C++ 中获得该功能……

标签: c++ haskell undefined-function


【解决方案1】:

谢谢@molbdnilo。 使用throw 简洁且完美:

int square(int x) {
  throw("undefined");
}

【讨论】:

    【解决方案2】:

    你也可以像下面这样使用断言:

    int square(int x) 
    {
      assert(0);
    }
    

    这样做的好处是不能被抓到,而且总是会失败。如果您忘记实现该功能,这将更好地保护您。

    【讨论】:

    • 不可捕捉性和防止遗忘是我完全错过的两个重点。谢谢。为了将该断言与其他“正常”断言区分开来,我 found out 可以将断言注释为 assert(0&&"undefined");
    • 但我不喜欢它是一个在发布版本中似乎被禁用的 C 宏。
    【解决方案3】:

    C++ 有纯virtual 函数,用于抽象基类。

    class foo {
      virtual void bar() = 0;
    };
    

    无法调用函数foo::bar(),实际上甚至无法创建foo 对象,但可以在foo 的派生类中重写它。但是,您可以为它定义一个派生类默认继承的定义。

    C++ 中与undefined 有点相似的另一件事是未初始化的函数指针。更安全、更现代的解决方案可能是 lambda 表达式或中止程序的 static 存根函数。

    undefined在实际使用中的含义类似于:一个占位符,如果你尝试实际调用它会导致程序崩溃,但它会正确编译并进行类型检查。对于单个目标文件,为未在任何地方定义的函数声明 extern 原型就可以完成这项工作。如果您要链接整个程序,则必须有某种定义(尽管函数指针可以绕过它,但以安全为代价),但它可以是存根。

    【讨论】:

    • 好话;不过,这在概念上与 Haskell 的 undefined 完全不同。
    • 它们是非常不同的语言。我会稍微扩展一下我的答案。
    最近更新 更多