提问人:Bwmat 提问时间:8/22/2023 最后编辑:Bwmat 更新时间:8/23/2023 访问量:98
在 C++03 中模拟 lambda 以在宏中进行流控制
Emulating lambdas in C++03 for flow-control purposes in macros
问:
我在头文件中有一些现有代码,需要在 C++03 和 C++11 的上下文中使用
它定义了一个宏,该宏接受 -style 格式字符串和参数,并使用该字符串进行格式化,将结果输出到 ,然后调用TABORT
printf
stdout
std::abort
从本质上讲,类似于
#define TABORT(...) do { fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); std::abort(); } while(0)
我想添加一些逻辑来捕获评估会引发异常的情况,从而阻止对 .例如,在以下内容中:__VA_ARGS__
std::abort
if (SomethingReallyBadHappened())
TABORT("Aborting because %s", GetReallyBadDetails().c_str());
如果抛出异常,我想确保调用中止(在这里,而不是在一些异常展开之后)。GetReallyBadDetails
所以,我做了这样的事情:
#define TABORT(...) do { fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); try { fprintf(stderr, __VA_ARGS__); } catch (...) { fprintf(stderr, "<Failed to evaluate abort message>\n"); } std::abort(); } while(0)
但是,当宏用于标记为 的函数时,这会导致 Visual Studio 中的 C4714 警告,可能是由于__forceinline
在某些情况下,编译器不会内联 机械原因。例如,编译器不会内联:
- 带有 try(C++ 异常处理)语句的函数。
因此,为了避免该警告(并保留以前确定需要内联内联的内联函数[我希望这是与分析一起完成的......]),我正在考虑做类似的事情
// In header
// Assume this is like std::function except construction from a lambda can't throw
template <typename Sig>
class function_ref;
using PrintAbortMsg = function_ref<void(const char*)>;
void [[noreturn]] do_tabort(const char* file, int line, function_ref<void(PrintAbortMsg &)> msgGenerator) noexcept;
#define TABORT(...) do_tabort(__FILE__, __LINE__, [&](PrintAbortMsg& print) { print(SprintfToStdString(__VA_ARGS__).c_str()); })
// In cpp
void do_tabort(const char* file, int line, function_ref<void(PrintAbortMsg&)> msgGenerator) noexcept
{
fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__);
try
{
msgGenerator([](const char* msg) { fprintf(stderr, "%s\n", msg); });
}
catch (...)
{
fprintf(stderr, "<Failed to evaluate abort message>\n");
}
std::abort();
}
我认为这在 C++11 的上下文中有效,但我不确定如何做一些适用于 C++03 的事情。我不想触及宏的现有用法。
答:
你工作太辛苦了。只需编写一个调用其析构函数的类即可。在宏中的左大括号之后创建该类的实例。它将被销毁并在右大括号处调用,无论该块是正常退出还是通过异常退出。如abort()
abort
struct AbortWhenDestroyed {
~AbortWhenDestroyed() { abort(); }
};
#define TABORT(...) do { \
AbortWhenDestroyed abort_me; \
fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
} while(0)
进一步研究的搜索词是“范围保护”。参见:std::experimental::scope_exit
您也可以使此类打印,如try/catch示例中所示。沿着这些思路:<Failed to evaluate abort message>
struct AbortWhenDestroyed {
~AbortWhenDestroyed() {
if (!normal_exit) {
fprintf(stderr, "<Failed to evaluate abort message>\n");
}
abort();
}
bool normal_exit = false;
};
#define TABORT(...) do { \
AbortWhenDestroyed abort_me; \
fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
abort_me.normal_exit = true;
} while(0)
如果 evaluate 引发异常,则不会执行该行,析构函数将在中止之前发出警告。__VA_ARGS__
abort_me.normal_exit = true;
上一个:在类中定义结构的 UML 类图
评论
struct
operator()
operator()
__LINE__
#line
operator()
[&]
__VA_ARGS__
operator()
abort()
abort()