【问题标题】:Returning completely different data types from a function从函数返回完全不同的数据类型
【发布时间】:2016-09-10 15:30:07
【问题描述】:

我正在尝试将我的编程语言的代码库从 Lua 翻译成 C++。我刚开始。我不是 C++ 专家,我希望我能在编写它的同时了解更多,但我已经遇到了一个让我停下来的障碍。

我现在正在编写词法分析器模块。它应该返回一个标记的双向链表,但是当然,在分析源代码时可能会发生错误,例如当多行注释或字符串没有结束括号等时。

当然,当我遇到错误时,我可以打印消息并结束程序。但是由于我想让这些错误易于处理,我能想到的最简单的事情就是return这些错误,这样如果错误处理函数得到那个错误,它就可以处理它,但是如果它一直到解释器,它的消息就会被打印出来。

在 Lua 中,这很容易。如果词法分析器函数在传递的文本中没有遇到错误,我可以让一个函数返回一个标记的双向链表(我在那里使用了无大小的数组,但这并不重要),或者一个要由调用者处理的错误对象。

但是,由于 C++ 必须指定返回类型,如果需要,我怎样才能让函数返回错误对象,以便正确处理它?还是我应该改变方法并使用退货系统以外的其他方式?

不幸的是,我无法搜索 Python 等语言的庞大代码库来了解它们如何处理这种情况,因此即使是指向这些文件的链接也会有所帮助。

【问题讨论】:

  • 继承 - 基类 Error 携带消息和位置 - 控制台/日志记录部分应该对此感到满意。从Error 派生您的特定类以携带您的“恢复代码”完成其工作所需的信息。啊,并将这些错误返回为std::shared_ptr。对于令牌列表的实际返回,在函数参数(指针/引用)中返回它们

标签: c++ return return-type


【解决方案1】:

如果仅用于错误处理,您可能希望使用exceptions,因为这是 C++ 中的标准错误处理机制。当然,您必须在某处捕获并处理这些异常,否则 C++ 程序将停止运行。

如果您确实需要一种方法来从单个函数中获取多种可能的返回类型,您可以尝试unions。这种方法的缺点是您需要一种方法来向函数的调用者指示您实际返回的类型,并且调用者需要检查各种可能性。

除此之外,我可以给您一个一般性建议:虽然我不知道您将代码库从 Lua 转换为 C++ 的动机,但我不建议您这样做只是为了让所有代码都可用C++,只要 Lua 代码符合您的目的。您很可能会遇到更多无法将语言功能从 Lua 充分翻译成 C++ 的情况。

如果您需要一种从 C++ 应用程序与 Lua 交互的方法,您可以尝试直接从 C++ 使用 Lua 和 Lua API++ library 之类的包装器。

【讨论】:

  • 您的意思是我的语言异常的 C++ 异常?这看起来很有用,我当然没有考虑过。至于 Lua 到 C++,它是为了可移植性、性能,甚至因为我找不到 Lua 的动态性的一些 bug 的来源。
  • 除此之外,我不太明白你对联合部分的意思。怎么能用这些?
  • 是的,我的意思是 C++ 异常。至于可移植性:在我看来,Lua 是一种解释性语言,并且已经非常便携,但你的里程可能会有所不同。性能可能是 Lua 的问题,但与性能一样:基准测试/测量它。有时您可能会得到意想不到的结果。我刚刚添加了一行关于 Lua API++ 库的内容,它是 Lua for C++ 的包装器。 Lua 和 C++ 之间可能还有其他类型的语言绑定,允许您从 C++ (重新)使用 Lua。可能值得检查。
  • 嗯,TBH C++ 异常已经让我免于大量样板代码:在 Lua 中,当我从另一个 parseExpression 调用 parseExpression 时,我必须检查它是否返回了表示表达式或错误对象,并在后一种情况下返回它。但是在 C++ 中,它们会自动返回,直到遇到 try / catch 块,所以是的。接受你的回答
【解决方案2】:

让词法分析器返回一个封装结果的对象和一个指示成功或失败的标志,例如

struct Result {
  bool isValid; //flag to indicate of the result is valid

  //result from the analyzer
  std::list<int> list; 
};

然后在词法分析器中适当地设置标志,例如抛出异常时将 isValid 设置为 false。

Result DoWork() {

  Result result;
  try {
    /*do real work*/

    result.list.push_back(42);
    result.isValid = true;
  }
  catch (...) {
    result.isValid = false;
  }

  return result;

}

int main() {

  Result result = DoWork();

  if (result.isValid) {
  ...
  } else {
  ...
  }


}

【讨论】:

  • 我已经对此深信不疑了。我应该详细说明携带消息和其他信息的结构,无论如何这是否比 Striezel 建议的更好(我的意思是 C++ 异常)?
  • 更多的是面向对象的。使用带有标志(可能是消息甚至异常)的结构(或类)与实际数据一起使用,将使函数 (DoWork) 的用户清楚地知道如何解释结果的含义。这将允许客户端决定当 isValid 为 false 时如何处理这种情况。或者,您可以只抛出异常并强制客户端处理该异常。
猜你喜欢
  • 2011-06-27
  • 1970-01-01
  • 2014-02-02
  • 2017-08-18
  • 1970-01-01
  • 1970-01-01
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多