我如何支持在 C++ 的异常处理宏中使用流?
How can I support using streams in an exception handling macro in C++?
我有一个像这样的小错误函数:
template<typename ErrorType>
void throwError(const std::string &file,
const std::string &function,
unsigned int line,
const std::string &msg = "") {
std::ostringstream errMsg;
errMsg << file << ":" << line << ":" << function << ":"
<< "\nError: " << msg << std::endl;
std::cerr << errMsg.str();
throw ErrorType(errMsg.str());
}
然后我有一些使用函数的宏:
#define INVALID_ARGUMENT_ERROR(msg) throwError<std::invalid_argument>(__FILE__, __func__, __LINE__, msg)
#define LOGIC_ERROR(msg) throwError<std::logic_error>(__FILE__, __func__, __LINE__, msg)
所以我能做到:
if (condition == bad)
LOGIC_ERROR("you did a bad");
但是当我想在错误消息中添加附加信息时,这很不方便,例如数字的值。
修改此函数以使其能够使用流而不是字符串的好方法是什么?所以我希望能够做到:
if (condition == bad)
LOGIC_ERROR("you did a bad because condition \"" << condition << " != " << bad);
我试过将 std::string string msg
更改为 std::ostringstream
,但不起作用。
如果您愿意稍微更改语法,则可以使用简单的辅助宏。给定您当前的函数模板...
template<typename ErrorType>
void throwError(const std::string &file,
const std::string &function,
unsigned int line,
const std::string &msg = "")
{
std::ostringstream errMsg;
errMsg << file << ":" << line << ":" << function << ":"
<< "\nError: " << msg << std::endl;
std::cerr << errMsg.str();
throw ErrorType(errMsg.str());
}
然后您可以定义...
#define THROW_HELPER(ex_type) \
for (std::stringstream ss; true; throwError<ex_type>(__FILE__, __func__, __LINE__, ss.str())) \
ss
#define INVALID_ARGUMENT_ERROR THROW_HELPER(std::invalid_argument)
#define LOGIC_ERROR THROW_HELPER(std::logic_error)
这些可以用作,例如...
LOGIC_ERROR << "extra messages go here";
请注意,目前在抛出异常的过程中创建了两个单独的 std::stringstream
实例,因此显示的代码可能应该 'compacted' 一点以防止 [留作练习 :-) ].
我提出一个不同的选择:libfmt!
#define LOGIC_ERROR(...) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, fmt::format(__VA_ARGS__))
用法:
if (condition == bad)
LOGIC_ERROR("you did a bad because condition {} != {}", condition, bad);
这种方法的缺点是如果格式字符串无效,fmt::format
将抛出异常。您可以使用 FMT_STRING()
宏在 compile-time 处检查它:
#define LOGIC_ERROR(string) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, string)
#define LOGIC_ERROR_P(string, ...) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, \
fmt::format(FMT_STRING(string), __VA_ARGS__))
我在这里创建了两个版本的 LOGIC_ERROR
,有和没有额外参数。根据参数的数量,可以在这两者之间进行单个宏调度,但这留给 reader.
作为练习。
我有一个像这样的小错误函数:
template<typename ErrorType>
void throwError(const std::string &file,
const std::string &function,
unsigned int line,
const std::string &msg = "") {
std::ostringstream errMsg;
errMsg << file << ":" << line << ":" << function << ":"
<< "\nError: " << msg << std::endl;
std::cerr << errMsg.str();
throw ErrorType(errMsg.str());
}
然后我有一些使用函数的宏:
#define INVALID_ARGUMENT_ERROR(msg) throwError<std::invalid_argument>(__FILE__, __func__, __LINE__, msg)
#define LOGIC_ERROR(msg) throwError<std::logic_error>(__FILE__, __func__, __LINE__, msg)
所以我能做到:
if (condition == bad)
LOGIC_ERROR("you did a bad");
但是当我想在错误消息中添加附加信息时,这很不方便,例如数字的值。
修改此函数以使其能够使用流而不是字符串的好方法是什么?所以我希望能够做到:
if (condition == bad)
LOGIC_ERROR("you did a bad because condition \"" << condition << " != " << bad);
我试过将 std::string string msg
更改为 std::ostringstream
,但不起作用。
如果您愿意稍微更改语法,则可以使用简单的辅助宏。给定您当前的函数模板...
template<typename ErrorType>
void throwError(const std::string &file,
const std::string &function,
unsigned int line,
const std::string &msg = "")
{
std::ostringstream errMsg;
errMsg << file << ":" << line << ":" << function << ":"
<< "\nError: " << msg << std::endl;
std::cerr << errMsg.str();
throw ErrorType(errMsg.str());
}
然后您可以定义...
#define THROW_HELPER(ex_type) \
for (std::stringstream ss; true; throwError<ex_type>(__FILE__, __func__, __LINE__, ss.str())) \
ss
#define INVALID_ARGUMENT_ERROR THROW_HELPER(std::invalid_argument)
#define LOGIC_ERROR THROW_HELPER(std::logic_error)
这些可以用作,例如...
LOGIC_ERROR << "extra messages go here";
请注意,目前在抛出异常的过程中创建了两个单独的 std::stringstream
实例,因此显示的代码可能应该 'compacted' 一点以防止 [留作练习 :-) ].
我提出一个不同的选择:libfmt!
#define LOGIC_ERROR(...) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, fmt::format(__VA_ARGS__))
用法:
if (condition == bad)
LOGIC_ERROR("you did a bad because condition {} != {}", condition, bad);
这种方法的缺点是如果格式字符串无效,fmt::format
将抛出异常。您可以使用 FMT_STRING()
宏在 compile-time 处检查它:
#define LOGIC_ERROR(string) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, string)
#define LOGIC_ERROR_P(string, ...) \
throwError<std::logic_error>(__FILE__, __func__, __LINE__, \
fmt::format(FMT_STRING(string), __VA_ARGS__))
我在这里创建了两个版本的 LOGIC_ERROR
,有和没有额外参数。根据参数的数量,可以在这两者之间进行单个宏调度,但这留给 reader.