从函数返回时以自动方式显示 source_location 信息

问题描述 投票:0回答:2

我有两个日志函数在进入和离开函数时显示,

void logEnter(const source_location location = source_location::current())
void logExit(const source_location location = source_location::current())
,显示的信息是函数名称和行。

现在我有一个函数

Foo
,它有多个返回语句。我想在输入函数时调用 logEnter (使用默认参数)(简单),并在返回时调用 logExit (使用默认参数)。问题是,我必须为每个返回添加一个调用(如果我想在许多函数上实现这一点,我会很痛苦)。

我想知道是否可以想出一个单行解决方案,即类似于

lock_guard
,只需在函数 Foo 的开头定义一些对象即可实现此目的。对于一个简单的类,问题在于析构函数不能接受任何参数,并且它应该获取调用者源位置,而不是析构函数位置。

我不需要关心异常。澄清一下,函数 Foo 已经实现了,所以我编辑的代码越少越好。

示例:

void logEnter(const source_location location = source_location::current()){
  cout << "Log, entering " << location.function_name() <<" at line "<< location.line() << endl;
}

void logExit(const source_location location = source_location::current()){
  cout << "Log, exiting " << location.function_name() <<" at line "<< location.line() << endl;
}

// Working implementation
string parity(int x) {
  logEnter();
  if (x%2 == 0) {
    logExit(); return "even";
  }
  logExit(); return "odd";
}

// Wish implementation
string parity(int x) {
  logFunctionGuard();
  if (x%2 == 0)
    return "even";
  return "odd";
}

调用 parity(3) 时,cout 终端应显示

Log, entering parity at line 10
Log, exiting parity at line 13
c++ c++20
2个回答
1
投票

这可能有点被诅咒,但你可以做

#define return logExit(); return

自动将 logExit 添加到所有 return 语句中。如果您只想将其应用于 Foo,请在函数 Foo 的上方编写宏,在下方编写

#undef return

但请注意,使用关键字作为宏标识符可能会导致 UB,因为它是一个保留的宏名称,正如 Jarod42 指出的那样。

另一种选择是编写一个简单的类

class LogExit {
public:
    LogExit(T t, std::source_location sourceLocation = std::source_location::current()){
        cout << "Log, exiting " << location.function_name() <<" at line "<< location.line() << endl;
    }
};

其中

T
是Foo的返回类型,它可以从
T
隐式转换。然后将 Foo 的返回类型更改为
LogExit
瞧。这不适用于 void,并且需要您将返回值转换回
T
(如果需要)。

否则,有 boost stacktrace 那么您可以定义一个没有成员的类,并从其构造函数和析构函数中打印您感兴趣的堆栈跟踪部分。


0
投票

我打算建议使用智能指针的删除器,例如这里:

#include <iostream>
#include <functional>
#include <memory>
#include <source_location>

using namespace std;

#define logFunctionGuard()                                       \
    logEnter();                                                  \
    const auto onExit = unique_ptr<char, function<void(char*)>>( \
        (char*)1,                                                \
        [location = source_location::current()](char*) {         \
            logExit(location);                                   \
        }                                                        \
    );

但不幸的是,这会为出口打印与入口相同的行。

更换

        [location = source_location::current()](char*) {

        [](char*, source_location location = source_location::current()) {

根本不提供正确的退出功能。

尽管如此,还是将其留在这里,并提供指向 Godbolt 的链接,作为其他人的灵感,因为评论太长了。

© www.soinside.com 2019 - 2024. All rights reserved.